Keywords · REVERSE

REVERSE

A REVERSE is a write-back block describing what happens when a value is written.

Format

The grammar of a single REVERSE line:

REVERSE ::= "REVERSE" type identifier
type ::= name [ "(" type { " " type } ")" ]
name ::= identifier { "." identifier }
identifier ::= letter { letter | digit }
A REVERSE keyword is followed by the type of the value written back and an identifier naming the block.

Usage

A REVERSE keyword can only live inside a FUNCTION keyword.

Inside a FUNCTION

In a function body, a reverse pins a write-back rule to the value it names.

FUNCTION Ui.Element SubmitForm
  INPUT Ui.Form.Result formData
  REVERSE Ui.Form.Result submissionReverse
    LET Ui.Form.Result result = Api.Client.ParseFormResult formData
    SET formDataState = result
A reverse inside a form-submit function, writing the parsed result back into state.

When something writes that value, the reverse runs — its forward body computes from the incoming value and the closing SET writes the result into outer state.

Can Contain

The indented lines of a REVERSE are its body, in order: a forward body, then a closing write-back.

Containing a LET

Zero or more LET bindings (and effect calls) make up the body, computing from the incoming value exactly as in a forward block. They prepare the value that the closing SET writes back.

REVERSE Maths.Integer countReverse
  LET Maths.Integer next = Maths.Integer.Increment countState
A binding in the reverse’s forward body, computed from the incoming value.

Containing a CALL

An effect call on its own line, doing work in the forward body before the closing write-back.

REVERSE Text draftReverse
  Analytics.Track "edited"
A bare call in the reverse’s forward body.

Containing a SET

SET is the single point where a write actually takes effect, and it must be the final statement(s) of the block — never before the body is done, and never outside a REVERSE. It pushes a value into an outer STATE: it names the state to write and the value to put there, written SET stateName = value. It carries no body of its own and opens no further lines. Because it only ever ends a REVERSE, the renderer lowers it to the reactive setter Reactive.Set(state, value) (Reactive::set in Rust, Reactive.set in Zig). Here a retry bumps a reload counter, the whole block ending in its SET:

REVERSE Logic.Maybe incrementFlag
  LET Maths.Integer currentCount = Maths.Integer.Increment refreshCountState
  SET refreshCountState = currentCount
The closing SET pushes the result into the outer state it names.

Targets

The same example, rendered to each target; the closing SET becomes the reactive setter on the last line of each block.

JavaScript

// a write-back: runs when submissionReverse is written
function submissionReverse() {
  var httpResponse = Network.Web.Client.Post(url, optionalBody, headers);
  var result = Api.Client.ParseFormResult(httpResponse);
  Reactive.Set(formDataState, result);   // SET pushes into outer state
}

TypeScript

Reactive.Reverse(submissionReverse, () => {
  const httpResponse = Network.Web.Client.Post(url, optionalBody, headers);
  const result = Api.Client.ParseFormResult(httpResponse);
  Reactive.Set(formDataState, result);   // SET pushes into outer state
});

Dart

Reactive.Reverse(submissionReverse, () {
  final httpResponse = Network_Web_Client.Post(url, optionalBody, headers);
  final result = Api_Client.ParseFormResult(httpResponse);
  Reactive.Set(formDataState, result);   // SET
});

Swift

Reactive.Reverse(submissionReverse) {
  let httpResponse = Network.Web.Client.Post(url, optionalBody, headers)
  let result = Api.Client.ParseFormResult(httpResponse)
  Reactive.Set(formDataState, result)    // SET
}

Go

Reactive.Reverse(submissionReverse, func() {
  httpResponse := Network_Web_Client.Post(url, optionalBody, headers)
  result := Api_Client.ParseFormResult(httpResponse)
  Reactive.Set(formDataState, result)    // SET
})

Rust

Reactive::reverse(submission_reverse, Box::new(move || {
  let http_response = network::web::client::Post(url, optional_body, headers);
  let result = api::client::ParseFormResult(http_response);
  Reactive::set(form_data_state, result);  // SET
}));

Zig

Reactive.reverse(submission_reverse, struct { pub fn run() void {
  const http_response = network.web.client.post(url, optional_body, headers);
  const result = api.client.parse_form_result(http_response);
  Reactive.set(form_data_state, result);   // SET
} }.run);

JSON

["S", "submissionReverse", "Ui.Form.Result", [
  ["=", "httpResponse", "Network.Web.Response", ["Network.Web.Client.Post", [], ["url", "optionalBody", "headers"]]],
  ["=", "result", "Ui.Form.Result", ["Api.Client.ParseFormResult", [], ["httpResponse"]]],
  [">", "SET", [], ["formDataState", "result"]]
]]

Related

A two-way parameter is an INPUT in BINDING mode, usually targeting a STATE — the same STATE a reverse's closing SET writes into. Bodies are built from LET bindings, and reversibility is explored in Context. Back to the language.