# `Rho.Dyn.Reuse`
[🔗](https://github.com/GenericJam/rho/blob/v0.1.0/lib/rho/dyn/reuse.ex#L1)

Incremental compiles: a proposal recompiles only the files that changed
(or depend on a change at compile time) and reuses the rest from its
parent generation, renamed. On a Moto G 2021 compiling the default
front from source takes about 33 s, and recompiling a module from its
stored Erlang code still about 350 ms (the Erlang compiler's passes):
24 s of a one-file change to the 68-module front. So a module is reused
by renaming its compiled binary instead; on a Mac that takes 56 ms for
the whole front, against 1.9 s through the Erlang compiler.

**What a generation records** (`deps`, stored next to its binaries,
`Rho.Dyn.Store.deps/2`), by the names the agent wrote
(`"Dyn.Notes"`):

  * per file, the modules it defines and the modules it needs at compile
    time (`Rho.Dyn.Trace`), or `nil` when that's unknown;
  * per module, the modules its compiled code names anywhere (calls,
    literals, attributes), from its debug info; a reused module names
    what its parent named.

**Which files are reused** (`plan/2`): an unchanged file whose needs are
known, none of which is *dirty*. A module is dirty if its file isn't
reused (changed, deleted, or itself dirty), or if its code names a dirty
module, directly or through others: a compile-time call into it may
reach the change. Repeated until nothing changes.

**Reusing** (`recompile/4`): the parent's binary with every
`Dyn.G<parent>.*` atom in its atom table, literals and term
chunks (debug info, attributes, docs, ...) renamed to
`Dyn.G<n>.*`. Code refers to atoms and literals by index, so it
is kept byte for byte, line table included: stack traces name the
parent generation's copy of the source, which is the same text. A
module whose code or literals still hold the parent generation's name
(a string built at compile time, say), or that the rename doesn't
understand, goes the slow way: the Erlang code in its debug info,
renamed, through the Erlang compiler. If that still holds the old name
or doesn't compile, it's compiled from source. Generations built by
another runtime (a Core update) are never reused from: the Keeper
rebuilds them whole.

# `deps`

```elixir
@type deps() :: %{required(String.t()) =&gt; map()}
```

# `empty`

```elixir
@spec empty() :: deps()
```

Empty deps: nothing known, nothing reused.

# `plan`

```elixir
@spec plan(deps(), MapSet.t(String.t())) :: MapSet.t(String.t())
```

The files of `deps` (the parent's) to reuse, given the files whose
source is the same as the parent's (`unchanged`).

# `recompile`

```elixir
@spec recompile(binary(), pos_integer(), pos_integer(), String.t()) ::
  {:ok, module(), binary()} | :error
```

Generation `to`'s version of `bin`, a module of generation `from`, for
source file `file`: `{:ok, module, binary}`, or `:error` when it has to
be compiled from source.

# `refs`

```elixir
@spec refs(module(), binary(), pos_integer()) :: [String.t()] | nil
```

The modules of generation `n` (by their written names) that `bin`'s code
names, other than itself; nil when it has no debug info (it might name
any).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
