The trio the author decided on 2026-09-20 is now all built: def is CL's defparameter — its initialiser runs on every daemon re-run, unguarded, so an edited initialiser repaints the same storage on C-c C-c plus re-run — defonce (Clojure's name for CL's defvar, per the author) initialises once behind the .init~once. flag, and defconst stays the image. One parse arm reads both forms; the difference is Ast.reinit, carried to Tast.global's grerun. Emit.startup_plan gives a def no guard flag, and Check.check_global lifts every def initialiser — zero and literal included — into global/<n>, so the host's startup reaches it through the function cell and a re-evaluated def swaps it (Session's def_inits; Emit.redefinition declares the cell for a non-sibling target). The old defvar spelling is refused with the rename and both compiling spellings, and every program, test, doc and editor list is swept — except sand.flan, the author's live WIP, whose seven defvar lines are flagged in FIX.org and keep its three dependent tests red on this branch.
47 lines
2.1 KiB
Plaintext
47 lines
2.1 KiB
Plaintext
;;;; A class, instances of it, and a session that changes the class.
|
|
;;;;
|
|
;;;; dev-class.flan already asks whether a *method* added to a running
|
|
;;;; program reaches a call site compiled before it existed. This asks the
|
|
;;;; harder half: whether the instances already in the program survive their
|
|
;;;; class being redefined. They are ordinary dyn maps held in a dyn global,
|
|
;;;; so the reload cannot touch them — a redefinition makes a program's
|
|
;;;; globals external and never re-initialises them, which is the whole of
|
|
;;;; "edit the code, keep the sand" — and what the editor sends is a new
|
|
;;;; constructor plus a registration of the class's new slot list. The
|
|
;;;; migration happens lazily, in the runtime, at the first touch after that.
|
|
;;;;
|
|
;;;; [instances] is a global rather than a local for exactly that reason: an
|
|
;;;; expression the editor evaluates is a thunk with a frame of its own, so
|
|
;;;; anything it is supposed to still be holding an hour later has to live
|
|
;;;; somewhere the thunk is not.
|
|
;;;;
|
|
;;;; The instances are pushed by the editor rather than by [main], and that
|
|
;;;; is not incidental. A (defclass ...) whose slots change is a constructor
|
|
;;;; whose signature changes, and the session refuses that wherever a
|
|
;;;; compiled caller of the constructor is left standing — a call site that
|
|
;;;; passes two dyn words into a three-parameter body leaves the third
|
|
;;;; holding a register, and a dyn word that is not a value is a wild
|
|
;;;; pointer. A [main] calling [(point 3 4)] would be exactly such a caller,
|
|
;;;; so this program has none and the instances arrive from thunks, which
|
|
;;;; leave nothing behind. test_session.ml pins the refusal itself.
|
|
;;;;
|
|
;;;; It keeps running rather than returning, for dev-class.flan's reason: an
|
|
;;;; expression typed at the editor is a thunk the agent runs at a frame
|
|
;;;; boundary, and a parked program has none.
|
|
(import agent "vendor:agent")
|
|
|
|
(defclass point [x y])
|
|
|
|
(defgeneric area [self] dyn)
|
|
|
|
(defmethod area point [p] (* (get p :x) (get p :y)))
|
|
|
|
(defonce instances dyn)
|
|
|
|
(defn main [] i32
|
|
(agent/start "/tmp/flan-dev-classes-fallback.sock")
|
|
(set instances (vec-new dyn))
|
|
(dotimes [i 4000]
|
|
(agent/wait 5))
|
|
0)
|