One IRef seam: watches/validators/meta over atom, var, and agent

add-watch/remove-watch/set-validator!/get-validator were atom-only; the
atom ctor ignored :meta and :validator; watching a var crashed. Now the
ARef contract is one seam: atoms keep their record slots (hot path
unchanged), every other reference type registers a predicate and stores
watches/validators in identity-keyed side tables, and notifies at its
mutation points. Vars notify on root changes (def on a watched var,
var-set outside a thread binding, alter-var-root — thread-binding sets
don't notify, like the JVM); agents notify per action. The def-var! wrap
costs two weak-table probes per def and does IRef work only on a watched
var.

Ctor options follow ARef: the validator gates the initial value
(IllegalStateException 'Invalid reference state' — also the class for
rejected swap!/reset!), :meta must be a map (else ClassCastException),
nil allowed. meta reads any reference through the identity side-table
(the type-gated fall-through is gone); alter-meta!/reset-meta! work on
non-var references.

Runtime-only (no re-mint). 9 JVM-certified corpus rows; spec entry; cts
baseline 5781 -> 5805 pass, 73 baselined namespaces (the residual error
in the watch namespaces is their STM ref section — refs stay out of
scope).
This commit is contained in:
Yogthos 2026-07-02 09:07:00 -04:00
parent 257f822825
commit f80f9aab4b
8 changed files with 203 additions and 42 deletions

View file

@ -77,14 +77,23 @@
(let ((p (dyn-find-binding v)))
(if p
(begin (set-cdr! p val) val)
(begin (var-cell-root-set! v val) (var-cell-defined?-set! v #t) val)))
;; a ROOT change is Var.bindRoot: validate, set, notify watches
;; (a thread-binding set does not notify, like the JVM).
(let ((old (var-cell-root v)))
(iref-validate v val)
(var-cell-root-set! v val) (var-cell-defined?-set! v #t)
(iref-notify v old val)
val)))
(error #f "var-set: not a var" v)))
;; alter-var-root: atomically apply f to the current root plus args.
(define (jolt-alter-var-root v f . args)
(let ((new (apply jolt-invoke f (var-cell-root v) args)))
(let* ((old (var-cell-root v))
(new (apply jolt-invoke f old args)))
(iref-validate v new)
(var-cell-root-set! v new)
(var-cell-defined?-set! v #t)
(iref-notify v old new)
new))
;; __local-var: a fresh free-standing var cell (not interned). with-local-vars