flan/conditions.org
Joseph Ferano ca954a47b5 Shorter
The cheatsheet was a document. It should fit on a screen: the syntax, what is
missing, the traps that are not in any error message, and the three ways it
stops. What was cut is either in spec-conditions.md or in the compiler's own
refusal, and both say it better.
2026-09-11 09:22:44 +07:00

58 lines
2.1 KiB
Org Mode

#+TITLE: Conditions and restarts — cheatsheet
#+STARTUP: showeverything
Why it is shaped this way: [[file:spec-conditions.md][spec-conditions.md]]. Something to poke at:
=conditions-play.flan==flan dev conditions-play.flan=, then ~C-c C-c~.
* Works
#+begin_src lisp
(signal c) ; Unit. Handler returns -> carry on. No handler -> no-op.
(error c) ; Never. Only a transfer gets past; else the program stops.
(handler-bind [(Type [c] body ...) ...] body ...) ; match by type, no hierarchy
(restart-case BODY ; BODY and every clause have the same type = the form's
(name [] CLAUSE) ...)
(invoke-restart 'name) ; Never. Innermost frame offering the name wins.
#+end_src
#+begin_src lisp
(defn fetch [n i32] i32
(restart-case (middle n) ; its value if nothing transfers
(use-placeholder [] -1)
(retry [] 7)))
(handler-bind [(AssetMissing [c] (invoke-restart 'use-placeholder))]
(fetch 2)) ; -1
#+end_src
~defer~ between the invoke and the target runs, innermost first, before the
clause body. ~errdefer~ does not.
* Not yet
~handler-case~ · ~find-restart~ · ~compute-restarts~ · restarts with
parameters · the dev-build break loop. Each refused by name with its reason.
* Gotchas
- *A handler closes over nothing.* It is lifted into its own function.
Accumulate into a global, or put the value on the condition.
- *A restart re-runs whatever sits between it and the target.* Control resumes
at the ~restart-case~, so a ~retry~ repeats side effects after it. Put the
~restart-case~ where re-entry is safe.
- *An unknown restart name is a hard stop.* No ~find-restart~ to test with.
- *No supertype*, so nothing can say "any condition".
- *~signal~ cannot hand a value back.* Deliberate (§1).
- A condition must be a *struct*. ~return~ is refused inside either form.
* Stops the program, exit 134
#+begin_example
unhandled AssetMissing
file.flan:3:25: no restart named nope is active
file.flan:4:7: a defer invoked a restart, which a defer may not do — ...
#+end_example