Calculations
A calculation derives a new reactive value from existing ones. Reactive.Calculate is the primitive
behind it. You rarely write it by hand; modules like Reactive.Maths are made
of calculations, so you usually compose those. It is worth seeing, because it explains how the forward
direction works and why Reactive folds “asynchronous” into the same idea.
Value, inside the closure
Because every value is wrapped, arithmetic on one directly is unavailable.
Reactive.Calculate gives you the one place where raw values are safe: it takes a closure that runs
as ordinary native code. Inside it, Reactive.Value(x) unwraps a reactive input to its raw value, you
compute in plain JavaScript, and you return a raw result.
const celsius = Reactive.State(Maths.Real)(20);
const fahrenheit = Reactive.Calculate(() => {
const c = Reactive.Value(celsius); // unwrap to a raw number
return c * 9 / 5 + 32; // native maths, return raw
});
Value and Calculate belong together: Value attaches to the calculation
that encloses it. Inside one, every input you read through Value is recorded as a
dependency, which is what makes the next part work.
Readiness propagates
Because a calculation knows exactly which inputs it read, it also knows their readiness. If any of them is locked (not ready yet), the calculation's result is locked too, so your closure's value stands in only for data that is present. The lock flows forward through every calculation built on top, without a line of code from you.
An input isn't ready
A value is locked, perhaps still arriving from the network.
The result locks too
Any calculation that read it is locked in turn, and so is anything derived from that.
Then it clears
When the value arrives, the calculations recompute and the locks fall away.
This is why Reactive unifies synchronous and asynchronous values. A figure waiting on a request is not ready; everything computed from it is not ready; the page shows that pending state; and when it resolves, the same calculations run again. You write identical code either way, and the framework tracks whether something has loaded.
Composing with modules
You rarely reach for Calculate to do arithmetic, because the maths operations are calculations
already. Maths.Real.Add, Multiply and the rest each take reactive values or
plain constants and return a reactive value, carrying locks through for you. Compose one operation per
line:
// fahrenheit = celsius × 9 ÷ 5 + 32
const scaled = Maths.Real.Multiply(celsius, 9);
const ratio = Maths.Real.Divide(scaled, 5);
const reading = Maths.Real.Add(ratio, 32);
The constants 9, 5 and 32 sit right beside the reactive
celsius; each operation takes them as they come, treating both alike. The same
operations run backward inside a reverse; that is exactly how the two-way Fahrenheit field on the
reversibility page is built.