compile/ref

Syntax: (ref SYM), or one of the typed forms: (ref (item OBJ KEY)), (ref (attr OBJ NAME)), (ref (dynamic GETFN [SETFN DELFN EMPTYFN])), (ref (constant VALUE)), (ref (memoized GETTER)), (ref (parameter NAME [DEFAULT])), (ref (environ KEY [DEFAULT])).

Behaviour: Yields a ref, a handle to a storage location, by the shape of the target: refq for a variable, ref-item and ref-attr for a subscript and an attribute, a DynamicRef over the supplied functions, a ConstantRef that refuses stores, a MemoizedRef that calls its getter on the first deref and keeps the answer, (ParamRef 'NAME) for a parameter, and an environ-ref into os.environ. deref reads through the ref and (set! (deref r) v) stores through it.

The dynamic and memoized refs demand-wrap their functions, so a Koskari lambda works directly as a getter or setter.

The reader spells (ref ...) with &: &name, &obj.attr, and &(item coll key), where the & touches what follows.

Examples:

var total 6
var xs #[1 2 3]

var r &total
var ri (ref (item xs 0))
(deref r)              ;; 6
(deref ri)             ;; 1
(set! (deref ri) 10)   ;; xs is now #[10 2 3]

The computed arms:

var store #{"n": 1}

var rd (ref (dynamic (lambda [] (item store "n"))
                        (lambda [v] (set-item store "n" v))))
(deref rd)             ;; 1
(set! (deref rd) 9)
(deref rd)             ;; 9

var rc (ref (constant 42))
(deref rc)             ;; 42

var calls #[]
var rm (ref (memoized (lambda [] (.append calls 1) "computed")))
(deref rm)             ;; "computed"
(deref rm)             ;; "computed", the getter ran once
(len calls)            ;; 1

See also: bind!, Bindings and refs, References and storage indirection.