Features · Composable

Composable

Because of the novel reversible updates and automatic asynchronous handling, code in Program is truly composable. Slot your functionality in wherever you want, and all of the long-range effects are handled automatically, without you having to modify other parts of the program.

Small surfaces, no glue

Every module is a boundary with a small reactive surface. It exposes only its data shapes and functions; everything inside is private. Because each piece is reactive, combining two modules is just using one's output as another's input. The runtime works out what depends on what, so there is no wiring to maintain.

FUNCTION Text FormatPrice
  INPUT Maths.Integer cents
  LET Maths.Integer dollars = Maths.Integer.Divide cents 100
  LET Text amount = Maths.Integer.ToString dollars
  = Text.Append "$" amount

Define FormatPrice once and use it anywhere a price appears; it recomputes wherever its input changes, with nothing else to wire up. Browse the building blocks in the modules.

Bindings compose, not handlers

Composition is more than passing values forward. A component can pass a changeable BINDING down into a sub-component and say what to do when it changes — and that sub-component can do the same again, on down the tree. No callbacks are threaded through the layers; each piece declares only its own reverse.

App source of truth TaskList list TaskRow row binding down change up
A binding is passed down; a change flows back up. Each layer declares only its own reverse.

Crucially, a component never knows what is behind a binding it is handed. It might be backed directly by state, or by another component's reverse — it cannot tell, and does not need to. It writes the binding; whatever is above deals with the rest. That opacity is exactly what lets the pieces snap together.

Long-range effects, handled

Because a change fans out in reverse through everything it composes with, the effects that are normally long-range — one edit updating state several layers away, and the loading and locking that come with it — are the runtime's job, not yours. Slot a feature in and the wiring that would usually ripple across the codebase simply does not need writing. The asynchronous handling rides the same paths.