Features · Contexts
Contexts
Some values belong to a whole region of a program rather than to a single function: the signed-in member, the current theme, an open connection, the node you are building into. A context makes such a value available by name to everything running within a scope, so you never have to thread it through every call in between.
A value in scope
Open a context with a name and a value, run some work, then close it. While it is open, any code below — however deep in the call tree — can ask for that name and get the value back, type-checked. Contexts nest: opening one with a name already in use saves the outer value and restores it afterwards, so an inner region can override what an outer one provided without disturbing it.
Each context is just an immutable entry on a stack, so capturing the whole set is cheap — which is part of what lets a running program be snapshot and resumed elsewhere.
The kinds of context
The standard library builds a small family of contexts on that one mechanism, each for a different shape of value:
- Input.
A read-only value placed in scope and read by name — an implicit argument shared by everything below, rather than one passed down by hand.
- Mutable.
A value that code in scope can update in place; when the scope closes you are handed the final value. Useful for a running total or a piece of working state.
- Array.
A collector for a list: open it, emit elements from anywhere below, and close it to get the gathered array — each element with a stable key so it stays reactive.
- Map.
The same idea keyed by name: emit key-and-value entries while in scope, and close it to get a map.
- Tree.
Gather nested branches into a tree, each node carrying its own payload — the shape behind a laid-out interface and other hierarchies.
- Mode.
A swappable set of named functions. Calls made in scope dispatch to whichever implementation is currently active, so the same description can be driven by a different backend just by changing the mode around it.