Features · Asynchronous

Asynchronous

All values in Program are automatically asynchronous, and it is completely transparent. There is no async, no await, and no promise to thread through your code; asynchronous work is just an ordinary reactive value.

A request is a value

A request is an ordinary value; when it resolves, the parts that depend on it recompute.

LET Network.Web.Response response = Network.Web.Client.Get "https://httpbin.org/get" null
LET Text body = Network.Web.Response.GetResponseBody response
Console.Line body

response starts empty and fills in when the request completes. body derives from it, so the moment the data lands the console line updates, exactly the way any other reactive value would.

Ready or not

Every value carries metadata alongside it — chiefly whether it is ready. A pending request is not ready; a value derived from it is not ready either, and so on, because any calculation with a not-ready input marks its own output not-ready. The status travels the graph by itself. It only matters at the edges, where a value is finally shown.

request pending body not ready interface spinner
Not-ready travels from the request through everything derived from it; the interface turns it into a spinner until the data lands.

Loading, errors and retries

The metadata carries errors too, the same way it carries readiness, so a failure anywhere surfaces wherever the value is used. Mark a state LOCKED to say it may be pending or carry an error:

STATE LOCKED Network.Web.Response response = null

The interface reads that lock, so the area showing the value gets a loading spinner for free, an error message with a retry button on failure, and the real content when it arrives — with no flags or wiring of your own.

Locking, in reverse

The reverse direction gets the same treatment. When a reverse is slow — it has to reach a server before it can write the real state — the runtime marks every piece of state that reverse will end up writing as not-ready, locking it for the duration. The whole reverse becomes a transaction.

Two useful things follow for nothing. The interface disables the control that would start a clashing change — a button that cannot yet be pressed, a box that cannot yet be ticked — so a second write cannot race the first. And the same lock drives the spinner, so the user sees exactly what is in flight and what they may do, with no wiring at all.