Skip to content

Latest commit

 

History

History
57 lines (34 loc) · 3.27 KB

File metadata and controls

57 lines (34 loc) · 3.27 KB

Mutation

The first main dimension. A Nu program exists to mutate Context; everything else is scaffolding around that mutation.

How mutation lands

Context changes only one way: a Ref in WRITE position carries a value into it. No Ref in WRITE, no landed mutation - regardless of what the surrounding atoms intend.

Two levels care about this:

  • atom level - the atom's kind says whether it mutates. Command and Action are mutating kinds; they intend to write. Whether they land a mutation depends on having a Ref in WRITE slot.
  • composition level - a composition mutates iff some atom inside it lands a mutation.

Observability

Because "intends to mutate" and "actually lands a mutation" can diverge, the honest question at each atom isn't "does this mutate?" but "does this atom contribute to some mutation somewhere?"

That question is observability. An atom is observable in its place iff:

  • it lands a mutation itself (own WRITE via a Ref), or
  • it yields a value consumed by an ancestor whose chain eventually lands a mutation.

A composition is observable iff at least one atom inside it lands a mutation.

An atom or composition with no eventual mutation on Context is non-observable. Non-observable final compositions are excluded from the Nu model. A Query-only final composition is meaningless: values evaporate with no mutating ancestor to consume them.

What this forces

The two paths to observability become the atom-kind split:

  • Refs are their own kind. They are the only path to Context, hence the only path to landing a mutation.
  • Mutate vs yield is a structural split. One kind that mutates (Command), one that yields (Query). Plus the hybrid that does both (Action).
  • No atom is dead by construction. Every kind sits on at least one path; there is no atom that neither mutates nor yields.

The observability matrix

The two paths are independent axes, not opposite poles. Crossing them gives four cells:

                 mutates: no         mutates: yes
yields: yes      (a) Query           (c) Action
yields: no       (d) non-observable  (b) Command
                     -> INVALID

a, b, c are the three live cells - each observable through at least one path. d is dead precisely because it is the joint absence of the other two. The opposite of mutation under observability is not value-return (itself a live path); it is d.

Addressless collapse

The gap between intends to mutate and lands a mutation shows up when a mutating kind has no Ref in WRITE - it's applied addressless, e.g. over a value-node like a Literal. The mutate path evaporates; only the yield path can still carry observability:

  • Command - no yield to fall back on. Collapses to cell d -> INVALID. It voids.
  • Action - the yield half survives -> degrades to Query (a).

So: without an address, Command voids and Action degrades. Literal([1,2,3]).append(4) voids; Literal([1,2,3]).pop() degrades to a Query yielding 3. A WRITE-position Ref is what makes an Action be an Action - lacking one, it falls back to its Query identity; only Command, having no yield, cannot survive the loss.

Forms (see later) inherit this: a method is offered iff its node avoids cell d - all Query and Action methods over a value-node, never a Command method.