;;;; The third element of a defonce, both ways. ;;;; ;;;; The rule, 2026-09-20: a type there is the zeroed static global it has ;;;; always been, and anything else is a dyn global initialised from that ;;;; expression at startup. So this file is one program holding both kinds ;;;; side by side, and every line it prints is a claim about which reading ;;;; one of its declarations got. ;;;; ;;;; There is no new lowering under any of it. The dyn half is exactly what ;;;; [(defonce x dyn )] already compiled to — the initialiser lifted into ;;;; the startup function that main calls after the runtime is up, and a ;;;; collector root pushed for the global before it runs — which is why this ;;;; program runs identically on both backends and why neither of them ;;;; learned anything for it. (defstruct Point [x i32 y i32]) ;; ── The type reading, which is every declaration that worked before ── ;; A primitive, a fixed array, a struct and a container: all four are types in ;; the third position, so all four are the zeroed statics they were. (defonce current-color i32) (defonce grid [2 [3 u32]]) (defonce origin Point) (defonce bytes (Vec u8)) ;; ── The value reading, which is the new spelling ───────────────────── ;; None of these names a type, so each is a dyn global holding the value its ;; expression produced before the program's own code ran. (defonce score 0) (defonce label "start") (defonce config {:level 1 :name "one"}) (defonce tally seeded) ;; A call, which is the shape the author kept writing: the file is read once, ;; at startup, into a global that outlives main. (defn load [] dyn {:rows 3 :cols 4}) (defonce game-data (load)) ;; And the value the bare symbol above was initialised from, declared *below* ;; it on purpose: which reading a defonce gets is decided with every name in ;; hand, not in the order the file was written. (defonce seeded i64 7) (defn main [] () ;; The statics, untouched: zero, zero, zero, and an empty Vec that is a real ;; empty Vec rather than a placeholder. (print current-color) (print " ") (print (at grid 1 2)) (print " ") (print (.x origin)) (print " ") (print (len bytes)) (println "") ;; The dyn globals, as their initialisers left them. (print score) (print " ") (print label) (print " ") (print (get config :name)) (print " ") (print tally) (println "") (print (get game-data :rows)) (print " ") (print (get game-data :cols)) (println "") ;; They are globals and not constants: each is assigned, and the map is ;; mutated in place through the same root the startup function filled. (set score (+ score 5)) (set label "done") (put config :level 2) (set current-color 3) (set (at grid 1 2) 9) ;; An allocation loop between filling them and reading them back, so the ;; collector runs with the run's own frames on the stack. A dyn global whose ;; root was not pushed reads back as a stale word here rather than as what ;; was stored. (dotimes [i 20000] (let [junk {:i i :s "forty-seven bytes of text to fatten each row"}] (put config :seen (get junk :i)))) (print score) (print " ") (print label) (print " ") (print (get config :level)) (println "") (print current-color) (print " ") (print (at grid 1 2)) (println ""))