Targets · JavaScript · Example

Example

The whole language in one short program — a module with a record, a tagged union, a function with per-platform native bodies, and a function that wires up state, a write-back and a return, then a block of global code that ties them into a small running application with a user interface — and the complete JavaScript it renders to, down to the run call and its drivers. The module is the one shown on the language page.

Contents

How a Program becomes JavaScript, in parts. Start with the introduction, then follow each part into the rendered output and the runtime it links against.

Every keyword, in one program

Each keyword has its own page under keywords; here they are all together — the MODULE declaring the pieces, then the global code beneath it that runs them as an application: a profile card that greets by name, shows a welcome row, and has a button that ages the profile up.

MODULE App

  TYPE Profile
    FIELD Text name
    FIELD Maths.Integer age

  TYPE Status
    OPTION App.Profile active
    OPTION Text pending

  FUNCTION Text Greet
    INPUT Text name
    NATIVE js    "return 'Hi ' + name;"
    NATIVE dart  "return 'Hi ' + name;"
    NATIVE swift "return \"Hi \" + name"

  FUNCTION Text Welcome
    INPUT BINDING App.Profile profile
    HOLE Text row
      INPUT Text line
    STATE Maths.Integer count = 0
    STATE LOCKED Network.Web.Response saved = null
    REVERSE App.Profile submit
      LET Network.Web.Response response = Network.Web.Client.Post profile
      SET saved = response
    LET Text label = Maths.Integer.ToString count
    = label


STATE App.Profile user = App.Profile "Ada" 36

LET Text greeting = App.Greet user.name
Ui.Content.Title greeting
App.Welcome user
  Ui.Content.Text line
Ui.Button.Integer.Increment user.age
  Ui.Content.Text "Older"

Rendered JavaScript

The whole program, rendered. The module is a nested object; Greet's js native body is spliced in; the function's inputs and holes are parameters, its state and write-back are runtime calls, and the trailing = is a return. Records and unions are plain immutable shapes in a reserved _ slot, each with a constructor that lifts its inputs through the reactive runtime (see construction and field access). At the foot, the global code becomes the run call, Program._Runtime.Run — the root run body, then the drivers the application needs.

var App = {};

// A record: a plain immutable shape in a reserved `_` slot, plus a constructor
// that lifts plain, reactive or locked inputs through Program._Runtime.Reactive.Calculate.
App.Profile = function (name, age) {
    return Program._Runtime.Reactive.Calculate(() =>
        new App.Profile._(Program._Runtime.Reactive.Value(name), Program._Runtime.Reactive.Value(age)));
};
App.Profile._ = class { constructor(name, age) { this.name = name; this.age = age; } };

// A union: one tagged shape, one constructor per option, lifted the same way.
App.Status = {};
App.Status.active  = (value) => Program._Runtime.Reactive.Calculate(() => new App.Status._('active',  Program._Runtime.Reactive.Value(value)));
App.Status.pending = (value) => Program._Runtime.Reactive.Calculate(() => new App.Status._('pending', Program._Runtime.Reactive.Value(value)));
App.Status._ = class { constructor(tag, value) { this.tag = tag; this.value = value; } };

App.Greet = function (name) {
    return 'Hi ' + name;                 // the js NATIVE body
};

App.Welcome = function (profile, row) {
    var count = Program._Runtime.Reactive.State(0);
    var saved = Program._Runtime.Reactive.State(null, true);
    Program._Runtime.Reactive.Reverse(submit, () => {
        var response = Network.Web.Client.Post(profile);
        Program._Runtime.Reactive.Set(saved, response);   // SET
    });
    var label = Maths.Integer.ToString(count);
    return label;
};

// the global code — the running application
Program._Runtime.Run(() => {
    var user = Program._Runtime.Reactive.State(App.Profile('Ada', 36));

    var _user_name = App.Profile._GetName(user);   // field getter, made on first use
    var greeting = App.Greet(_user_name);
    Ui.Content.Title(greeting);

    App.Welcome(user, (line) => { Ui.Content.Text(line); });

    var _user_age = App.Profile._GetAge(user);   // two-way accessor for user.age
    Ui.Button.Integer.Increment(_user_age, () => { Ui.Content.Text('Older'); });
},
    Ui.Dom.Driver('app'),        // mount the interface into the page root
    Network.Web.Driver(),        // serve the request App.Welcome's submit makes
);

Construction and field access

The shapes above are only half the story. Every value in Program is reactive: an argument may be a plain value, a reactive value, or a locked (still-loading) reactive value, and anything derived from it must carry that state forward. Two moments need care — building a record or union, and reading or writing its fields.

Constructing — the type or option name

Calling a type name (App.Profile name age) or a union option (App.Status.active profile) does more than new the shape. It pulls each argument through Program._Runtime.Reactive.Value inside a Program._Runtime.Reactive.Calculate, so plain and reactive inputs both work — and, crucially, if any input is locked the whole constructed value is locked too:

App.Profile = function (name, age) {
    return Program._Runtime.Reactive.Calculate(() =>
        new App.Profile._(Program._Runtime.Reactive.Value(name), Program._Runtime.Reactive.Value(age)));
};

Program._Runtime.Reactive.Calculate remembers every value unwrapped with Program._Runtime.Reactive.Value during its callback and, if one of them is locked, marks its own result locked. So a Profile built from a still-loading age is itself loading until the age arrives — the loading state propagates with no explicit checks. The runtime page covers Calculate and Value in full.

Reading a field — and writing it back

profile.name is a reactive, two-way projection. It lowers to a temporary that calls the field's generated getter — one line, made on demand just before the field is first read in a scope, and reused for every later read or write of it. The temporary is named for the value and the field, with a leading underscore and another between them (_profile_name), so it can never collide with a program name:

var _profile_name = App.Profile._GetName(profile);   // made once, on first use
Ui.Content.Text(_profile_name);

The getter is generated onto the record's reserved _ slot — TYPE shows how — and runs the read inside a Calculate, so a locked profile yields a locked name. When profile is a two-way binding the getter returns a two-way accessor, so that same _profile_name temporary is also the write target: Program._Runtime.Reactive.Set(_profile_name, next) rebuilds the record with the changed field and stores it back. A field read and written in one scope therefore share a single temporary, and nothing is mutated in place.

A union option reads the same way, through its generated accessor — the payload, or a native null at depth one when the option is not set:

var _status_active = App.Status._OptionalActive(status);   // status.active

Where the generated helpers live

Every generated name here carries an underscore, so none of it can clash with a name the program defines: the raw immutable class and the getters sit on the record's reserved _ slot (App.Profile._, App.Profile._GetName), and each on-demand temporary is _-prefixed too (_profile_name). Since _ is illegal in a Program identifier, user code can never name, call, or clash with any of it. That is the phase-one fix for a phase-zero hazard, where a generated helper such as Profile.GetName shared the program's own namespace and could collide.

The run call and its drivers

The global code at the foot of the program is the root — the run body the runtime executes on every cycle. In the render above it is the first argument to Program._Runtime.Run; everything after it is a driver. This application needs two: the interface driver, which mounts the emitted interface into a root element on the page, and the network driver, which serves the request App.Welcome's write-back makes.

The first argument is the program: run once, then re-run whenever a value it read is written from outside. Each cycle the root emits interface descriptors into context channels and the drivers drain them, reconciling the real DOM and network (see drivers and runtime). The Older button closes the loop: Ui.Button.Integer.Increment is given the two-way user.age accessor and, on click, increments it — rebuilding the profile with the new age and storing it — so the next cycle re-renders the title and row from the updated state. The write-back itself lives inside the button component, not in user code; a SET only ever appears inside a REVERSE, as in App.Welcome's submit above.

The entry point sits in the reserved Program._Runtime namespace — the same underscore convention that walls off App.Profile._, so this runtime glue can never clash with anything the program itself names. The friendlier Program.Application(root, [drivers]) on the entry-point page is a thin public wrapper over exactly this call.

Reading it

Indentation becomes nested closures: the REVERSE body is a () => { … } block, and any indented interface would nest the same way. The dotted names pass straight through — Network.Web.Client.Post, Maths.Integer.ToString — see naming considerations. How each keyword maps, one by one, is on keywords.