flan/test/programs/dev-classes.flan
Joseph Ferano a4c6b996ff def re-runs its initialiser, and defvar is renamed defonce
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.
2026-09-21 07:12:04 +07:00

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)