Atom

type Atom<T> @abstract =
    var value : T
    let callbacks = StdList.new

    def subscribe (f : T * T -> Unit) =
        callbacks.add f
        Token { callbacks.remove f }

Atom is a container that stores a value and notifies about its changes.

type MutAtom<T> @[mut_of Atom] =
    inherit Atom<T>

    def set (x : T) =
        if x == value then return

        let prev_x = value
        value = x

        for f in callbacks do
            f prev_x x

MutAtom is a mutable version of Atom. MutAtom and mut Atom are synonyms.

type Token =
    let f : Unit -> Unit
    let mut is_discarded = false

    def discard =
        assert not is_discarded
        is_discarded = true
        f ()

The subscribe method returns Token that allows to cancel a subscription.

var obs position = Vector3.new
var obs origin = Vector3.new

val global_position@obs = origin@obs + position@obs

let token = position@atom
    |> subscribe { prev_v v -> println "position changed from $prev_v to $v" }

The position and origin bindings are represented by MutAtom<Vector3> objects. Every change causes recalculation of global_position.

The @atom modifier returns a container. Braces define a closure.

let tuple_atom = (position@atom, origin@atom) |> to_atom

let sum@atom = tuple_atom.map { u, v -> u + v }

to_atom transforms a tuple of atoms into an atom of tuples. The tuple_atom binding is of type Atom<(Vector3, Vector3)>.

The map method of Atom receives a closure of type (Vector3, Vector3) -> Vector3 as an argument and returns an Atom<Vector3> object. The @atom modifier on the sum binding hides the container. Accessing sum will return the value of the container's value field, and assignment will call the set method.

The comma between u and v in the closure parameter list indicates that they are elements of a tuple. Parentheses are optional if the tuple is the only parameter.