;;;; The dev-build break loop — spec-conditions.md §2. ;;;; ;;;; An unhandled error used to kill the program. Here it stops instead, on the ;;;; frame that erred with nothing unwound, and waits for someone to pick a ;;;; restart. Two of them, and the run takes a different one each time, so a ;;;; break loop that always resumed the same way could not pass. (import agent "vendor:agent") (defstruct Missing [id i32]) (defn fetch [n i32] i32 (restart-case (do (error (Missing {.id n})) 0) (use-placeholder [] :report "Answer -1 for the missing value" -1) (retry [] 7))) ;;; Two frames offering the same name, which §4 says resolves to the inner one ;;; and only ever the inner one. The outer clause is therefore on every list a ;;; break loop prints and reachable from no name at all, which is why a restart ;;; is taken by *index* now. 900 is the proof: it is the only value in this ;;; file that by-name lookup cannot produce. (defn shadowed [n i32] i32 (restart-case (+ (restart-case (do (error (Missing {.id n})) 0) (retry [] 5)) 100) (retry [] 900))) (defstruct Other []) ;;; A handler-case establishes a restart of its own, under a name nobody wrote, ;;; and a break loop inside it must not offer that one: it is reached through ;;; the form's handler, which carries the condition in. Only [keep] is listed. (defn caught [n i32] i32 (restart-case (handler-case (do (error (Missing {.id n})) 0) [(Other [_o] 5)]) (keep [] :report "Answer 42" 42))) (defn main [] i32 (agent/start "/tmp/flan-break.sock") (print (fetch 1)) (println "") (print (fetch 2)) (println "") (print (shadowed 3)) (println "") (print (caught 4)) (println "") 0)