Reversibility

Reversibility is the idea that sets Reactive apart. Deriving a value from state is a forward calculation, read-only. A reactive value can also have a way back: a separate reverse function that takes a new result and sends it into the state behind it. Join the two and you have a value that reads forward and writes backward. Genuinely two-way, and a single declaration carries both directions.

forward: compute reverse: the way back

Forward and reverse are separate

Forward and reverse are kept apart, because they are not always mirror images. A forward calculation might read several inputs and combine them, and the way back could update just one of them, or none, or something else entirely. Inverting an arbitrary calculation is unreliable, so you write the reverse yourself. You build the forward direction by composing reactive operations, one per line, each a small calculation; write the reverse as a separate Reactive.Reverse; and join the two halves with Reactive.Binding.

const celsius = Reactive.State(Maths.Real)(20);

// forward: fahrenheit = celsius × 9 ÷ 5 + 32, one reactive step per line
const scaled  = Maths.Real.Multiply(celsius, 9);
const ratio   = Maths.Real.Divide(scaled, 5);
const reading = Maths.Real.Add(ratio, 32);

// reverse: still reactive code, so it composes with the same operations
const writing = Reactive.Reverse((f) => {
  const offset  = Maths.Real.Subtract(f, 32);
  const widened = Maths.Real.Multiply(offset, 5);
  const back    = Maths.Real.Divide(widened, 9);
  Reactive.Set(celsius, back);
});

// bind the two halves into one two-way value
const fahrenheit = Reactive.Binding(reading, writing);
A two-way Fahrenheit field built from a forward and a reverse

Every line works on reactive values, keeping raw numbers out, even inside the reverse, which runs as reactive code, so it reaches for Maths just like the forward direction. Reading fahrenheit.value follows the forward chain. Calling Reactive.Set(fahrenheit, 212) runs the reverse, which walks the operations back to 100 and sets celsius. The two directions are described independently and bound together, so you tell Reactive exactly how to undo your calculation. A readable half and a writable half are exactly what a reactive value is made of.

Set flows backward

Reactive.Set is the whole write path, and it is polymorphic. Set a piece of state and the value is stored directly. Set a derived or bound value and its reverse runs; because a reverse typically calls Set on its own inputs, the edit cascades backward through the graph until it reaches plain state at the roots.

1

Set a result

An edit targets a derived value, say a formatted or converted figure shown on the page.

2

Reverse runs

Its reverse function receives the new value and sets the inputs it was calculated from.

3

Cascade to state

Each of those sets may run a further reverse, until the change lands in the underlying state.

Interaction through bindings

This is why interaction in Reactive stays simple. A DOM interaction does exactly one thing: it Sets a two-way binding to a new value, and the reverse cascade carries that change into state on its own. Components expose bindings, and anyone can update them.

Interactions differ only in where the new value comes from:

provided value

A button

The value is already known in code: a flag, the next number, a chosen option. Pressing the button sets a binding to that value; the press only triggers the set.

value from element

An input

The value lives on the element. Binding an input's value to a settable makes it two-way: what is typed is written straight back through the reverse, and the binding is the wiring.

Why it matters

In most frameworks, two-way binding is stitched together by hand: a value flows out to the view, and a separate event handler you wrote flows the user's change back in. The two directions are unrelated code that you keep in sync yourself.

Reversibility collapses that into one declaration: describe how a value derives, and the way back comes with it. The interaction model above is the same idea seen from outside; every event is a Set, and the reverse does the rest.