git » homepage.git » commit e46e6b3

Clarify control-flow graph terminology and shorten the appendix

author Alan Dipert
2026-11-10 20:16:33 UTC
committer Alan Dipert
2026-11-10 20:16:33 UTC
parent 9a8caa11a21b835accd016a65cde43330356227f

Clarify control-flow graph terminology and shorten the appendix

md/_MutableLocals.md +3 -13

diff --git a/md/_MutableLocals.md b/md/_MutableLocals.md
index 71bfa40..6ab5626 100644
--- a/md/_MutableLocals.md
+++ b/md/_MutableLocals.md
@@ -59,7 +59,9 @@ Let's use a smaller program so we can see the machinery:
 ;; => 45
 ```
 
-With the loop exposed, we can turn the program into operations and arrows: `setq` becomes a write, `if` chooses an edge, and `recur` leads back to the test. This is a [control-flow graph](https://www.cs.cornell.edu/courses/cs4120/2026sp/notes.html?id=traces). Each node is a _basic block_: a straight-line sequence of operations ending in a jump, a choice of successors, or an exit. Here is a simplified view, omitting temporary copies and the loop's discarded nil result:
+With the loop exposed, we can turn the program into a [control-flow graph](https://www.cs.cornell.edu/courses/cs4120/2026sp/notes.html?id=traces). Each _node_ represents a _basic block_: a straight-line sequence of operations ending in a jump, a conditional branch, or an exit. Each _edge_ represents a possible transfer of control from one block to another, drawn as an arrow.
+
+`setq` becomes a write inside a block, `if` chooses between outgoing edges, and `recur` leads back to the loop's test. Here is a simplified view, omitting temporary copies and the loop's discarded nil result:
 
 ```mermaid
 flowchart TD
@@ -196,15 +198,3 @@ To interrupt a function before it returns, you can throw something. [flambard/ta
 A jump that stays in one function gives the compiler another option. My [2020 JACL paper, §3.3.3](https://tailrecursion.com/~alan/documents/jacl-els-2020-draft.pdf#page=4) describes compiling Common Lisp's local `GO` operations into JavaScript's labeled `continue`. If all jumps to a `TAGBODY` are local, its generated `try`/`catch` disappears too.
 
 That's the division of labor I'd want in a fuller `tagbody`: use Blacktide-style compilation wherever a jump can become ordinary control flow, and reserve exception unwinding for exits through function calls. Both paths still owe us our `finally` blocks. Blacktide currently sticks to its compiled region.
-
-Back in Clojure, the practical differences are:
-
-| Library | Where changing state lives | Where a jump can go |
-| --- | --- | --- |
-| Blacktide | Lexical locals assigned with `setq`/`psetq` | An explicit label in the same compiled region |
-| flambard/tagbody | Separate storage; its example uses `with-local-vars` | Through function calls to an enclosing `tagbody`, matched by label name |
-| Farolero | Separate storage, such as atoms or volatiles | Through function calls to a particular active `tagbody` |
-
-Blacktide spends its compiler machinery on the problem we started with: updating our own little variables inside an algorithm.
-
-Both [tagbody](https://github.com/flambard/tagbody/blob/05352cd75cc218814cd98c3676f8cac26b0fe4e9/src/tagbody/Goto.clj) and [Farolero](https://github.com/IGJoshua/farolero/blob/6dbd299d25b37d22370a3134541bc49bb5c41273/src/java/farolero/signal/Signal.java) suppress stack-trace construction for their signals. A speed ranking needs benchmarks; “exceptions are slow” doesn't get to count as one.