;;;; What a variable reads as while an assignment to it is stopped part-way. ;;;; ;;;; half-write.flan asks the same question from inside the program, after the ;;;; frame has been abandoned. This one asks it from outside, at the break — ;;;; which is where it was first noticed, and where a local can be looked at ;;;; at all: a half-built local is invisible to the program (its name is not ;;;; in scope until the value lands) and perfectly visible to an editor ;;;; reading the frame. ;;;; ;;;; Three turns of one loop and two stops, so a single session answers both ;;;; halves. Nothing here handles the condition, so each stop lands in the ;;;; break loop with the program's own `continue` on offer. ;;;; ;;;; turn 0 — both the local and the global are built whole: 1 1 5 1. ;;;; turn 1 — signalled while the *local* is being built. At the stop the ;;;; slot still belongs to turn 0 and has to read 1 1 5 1 whole, ;;;; not 2 2 . 1 with the first half of turn 2 in it. ;;;; turn 2 — resumed, the local is rebuilt, and then the signal comes from ;;;; inside the *global's* assignment. At the stop the global has ;;;; to read turn 0's 1 1 5 1, not 3 3 5 1. (import agent "vendor:agent") (defstruct Boom [why i32]) (defonce colors [4 u32] [9 9 9 9]) (defonce spare [4 u32] [9 9 9 9]) (defonce skipped i64) (defn blow [] u32 (error (Boom {.why 1})) 0) ;;; One element of each literal, arranged so that each turn stops in at most ;;; one place and the two stops are in different ones. (defn in-local [n i32] u32 (if (= n 1) (blow) (u32 5))) (defn in-global [n i32] u32 (if (= n 2) (blow) (u32 5))) (defn work [] () (dotimes [i 3] (restart-case (do (let [v [(u32 (+ i 1)) (u32 (+ i 1)) (in-local i) (u32 (+ i 1))]] (set spare v)) (set colors [(u32 (+ i 1)) (u32 (+ i 1)) (in-global i) (u32 (+ i 1))])) (continue [] (set skipped (+ skipped 1)))))) (defn main [] i32 (agent/start "/tmp/flan-dev-halfwrite-fallback.sock") (work) (dotimes [i 4000] (agent/wait 5)) 0)