Context

A semantic scope moves values in two directions. Values flow in when a nested function reads a value declared in the scope around it, read down the call stack through ordinary closure capture. Values flow out when a nested function emits a value that an enclosing scope collects, gathered up the call stack. Both directions belong to the same scope, so both live on this page.

Values in: closures

A value declared in an outer Reactive.Function is captured by the functions defined inside it. The inner function reads the value straight from the closure, however deep, with nothing passed by hand. This is the way a value flows down a scope: it is in scope, so it is available.

const Select = Reactive.Function('Select', () => {
  // state declared in the outer function
  const selected = Reactive.State(Maths.Integer)(0);

  // an inner function captures selected from the closure
  const Option = Reactive.Function('Option', () => {
    const index = Reactive.Argument(Maths.Integer);
    // read selected here — no prop threaded through
    Button.Set(selected, index, () => {
      Content.Text("option");
    });
  });

  Option(0);
  Option(1);
});
A one-of-many group hands its selected state to each option through the closure

The group owns selected; each option reads and writes it because it is in scope. Closures replaced the earlier ambient mechanism, so a value shared down a scope is now the value already in scope.

Values out: emit and gather

Values also travel the other way. Reactive.Emit(channel, value) pushes a value onto a named channel. A Reactive.Gather(channel) in an enclosing function collects everything emitted below it. A channel behaves like a closure variable in reverse: where a closure flows a value down into nested scopes, a gather flows values up out of them.

const List = Reactive.Function('List', () => {
  // collect everything emitted on 'items' below here
  const items = Reactive.Gather('items');
  // items is the array of everything emitted below; build the output from it
});

const Row = Reactive.Function('Row', () => {
  const label = Reactive.Argument(Text);
  // push a value up onto the 'items' channel
  Reactive.Emit('items', label);
});
A container gathers what its children emit

Typed forms name the value on the channel. Reactive.Emit(Text)('items', value) emits a value of a given type, and Reactive.Gather(Text)('items') collects that type. This is how structural output is assembled: a list, a DOM tree, any container gathers what its children emit and builds the result from it.

Why one page

Closures and gathers are the same scope read from both ends. A closure carries a value down into the functions a scope contains; a gather carries values up out of them. Naming a channel points a value at the scope that will collect it, the mirror of a name already in scope for the functions below to read. One scope, two directions.