# Refs Refs are Deft's mutable-state primitive: a single cell holding one value, read with `deref` and updated with `reset!` or `swap!`. Every other collection is persistent — operations return new values — so a ref is how you express "this one spot may change": counters, caches, and the module-level state maps that TUI apps carry. These bare functions are compiled into every runtime and need no import; for the scheduler that shares them across coroutines, see Concurrency. There are two ref scopings with the same surface (`deref`, `reset!`, `swap!`, `add-watch`, `remove-watch`): - Anonymous refs (`[ref v]`) — value-scoped cells: created per call, passed around, held in data, GC'd when dropped. - Binding cells (`[var x]`) — the cell behind a module `def`; `$x` auto-derefs it in expressions. `def` rebinding writes the root silently; only explicit `reset!`/`swap!` through the cell fire watchers. Binding cells print as `#<var name>` (anonymous cells as `#<ref …>`). One mechanism, two scopings: `def x 1` is a silent `reset!` of the named cell (created on first definition) and `$x` is a silent `deref`. An anonymous ref is the same cell reached as a value rather than a name, so it takes the explicit verbs and gains addressability — pass it without importing the defining module, hold one per instance, embed it in data. Watching works on both; `[var x]` is what hands you the named cell. ## Functions | Function | Purpose | |---|---| | `ref value` | Create an anonymous ref holding `value` | | `deref r` | Read the current value (ref or binding cell) | | `ref? x` | True when `x` is a ref cell (either scoping) | | `var? x` | True when `x` is a binding cell (`[var x]`) | | `reset! r value` | Store `value`, return it, and fire watchers | | `swap! r f args...` | Call `(f current args...)`, store and return the result | | `add-watch r key fn` | Register watcher `fn` under `key` | | `remove-watch r key` | Remove the watcher under `key` | `swap!` calls the function as `(f current args...)` — the current value first, then any extra arguments — and stores the return value. `reset!` ignores the old value entirely. Both return the new value and fire every registered watcher synchronously, in registration order, with `(key cell old new)`; watchers fire on every call even when the new value equals the old one. `incr` is ref-aware: on a slot holding a ref it increments the ref's payload and fires watchers — `[incr counter]` is the counter idiom, equivalent to a `+1` `swap!`. Refs are compared by identity, not contents: two refs holding `%{}` are still different values. `deref` of a non-ref returns `nil`, so use `ref?`/`var?` when a value's type is not guaranteed. `add-watch` and `remove-watch` return `nil`; adding under an existing key replaces that watcher. Refs are shared by reference within one runtime, so coroutines on that runtime see each other's updates. They are not only for concurrent code, though: reach for one whenever you want a mutable cell with stable identity, or a place to hang `add-watch` reactions. Deft's scheduler is cooperative — coroutines switch only at explicit yield points (`yield`, `await`, `sleep`) — so a lone read or write cannot be preempted midway, and a read-modify-write whose function does not suspend is atomic. Notes — the API borrows Clojure's `atom` vocabulary (`deref`, `swap!`, `reset!`, `add-watch`), but the semantics diverge: - There is no `compare-and-set!` and no validator support. - Update closures passed to `swap!` must not suspend (`await`/`sleep`/`yield`): a suspending closure lets another coroutine update the cell while it is suspended, and the resumed write is last-writer-wins — there is no compare-and-retry. Keep update functions pure and non-suspending. - Refs are not a cross-runtime primitive — separate runtimes talk over `pub/*` or `rpc` (see Concurrency). ## Examples
def counter [ref 0]

[deref $counter]                            # => 0
[reset! $counter 5]                         # => 5
[swap! $counter {|n| ($n + 1)}]             # => 6
[incr counter]                              # => 7 (ref-aware +1)

[ref? $counter]                             # => true
[ref? 42]                                   # => false
Extra `swap!` arguments are appended after the current value:
[swap! $counter {|n step| ($n + $step)} 10] # => 17
The state-map pattern keeps related fields in one ref; updates go through `swap!` and reads through `deref`:
def state [ref %{ :count 0 :label "Clicks" }]

def bump {||
    [swap! $state {|s| [assoc $s :count ($s~count + 1)]}]
}

[bump]
[bump]
echo [deref $state]~count                   # => 2
Watchers observe every update — useful for persistence, logging, or invalidating a cache:
def a [ref 0]

[add-watch $a :log {|k cell old new|
    echo "change:" $old "->" $new
}]

[reset! $a 5]                               # prints: change: 0 -> 5
[remove-watch $a :log]
[reset! $a 9]                               # no output
Binding cells are watchable the same way — but only explicit mutation fires, not `def`:
def status "idle"

[add-watch [var status] :log {|k cell old new|
    echo "status:" $old "->" $new
}]

def status "busy"                    # no output (def is a silent root write)
[reset! [var status] "done"]         # prints: status: busy -> done
$status                              # => "done"
## See Also - Set and Def — binding cells, `[var x]`, and redefinition semantics - Concurrency — `deftask`, `defcoro`, and per-runtime state - Types and Protocols — how values dispatch - Maps — the persistent maps refs usually hold