| author | Alan Dipert
<alan@tailrecursion.com> 2026-11-10 19:59:22 UTC |
| committer | Alan Dipert
<alan@tailrecursion.com> 2026-11-10 19:59:22 UTC |
| parent | 27a0bc8f701efb92c596bb569e3495846fc2e68f |
| md/_MutableLocals.md | +3 | -3 |
diff --git a/md/_MutableLocals.md b/md/_MutableLocals.md index c5776d8..71bfa40 100644 --- a/md/_MutableLocals.md +++ b/md/_MutableLocals.md @@ -4,8 +4,6 @@ Hey, so, I've been thinking about mutable local variables in Clojure. Is that OK The Clojure situation has been explained to me. I'm totally down with the philosophy. Stable identities, immutable values, first-class state management. A more civilized, decomplected age. But I gotta level with you. Sometimes I have these intrusive thoughts about mutating local variables. I'll be reading an imperative algorithm in pseudocode, Java or C, and—please don't tell anyone about this—I'll think: man, it would be pretty sweet to port this directly without translating it into atoms or `loop`/`recur` and whatnot. -I mean, under the covers, the JVM certainly has no inherent moral objection to overwriting a [local-variable slot](https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-2.html#jvms-2.6.1). Clojure's own compiler even reuses those slots to _implement_ `loop` and `recur`. But I'm not allowed to assign to an ordinary lexical local myself? That heady stuff is only for the elite class of compiler writers, I guess? Is it ungrateful of me, as a mere user, to not be entirely satisfied with the privilege of supplying replacement values to approved recursion points? - Here's an example of the kind of stuff I'd like to write on occasion. This function counts inversions in a vector: pairs where an earlier element is greater than a later one. ```clojure @@ -25,7 +23,9 @@ Here's an example of the kind of stuff I'd like to write on occasion. This funct Nothing crazy, just setting a happy little variable `n` inside nested loops. I'm still here, by the way. Nothing terrible happened. -If you find yourself warming to these shenanigans, then I have some good news. This is a real thing that can be done, all thanks to the `loop`/`recur` constructs I just finished griping about. You see, [`recur`](https://clojure.org/reference/special_forms#recur) evaluates its arguments, rebinds the loop locals, and starts the loop body again. In [Clojure's compiler](https://github.com/clojure/clojure/blob/clojure-1.12.6/src/jvm/clojure/lang/Compiler.java#L7156-L7227), that becomes argument evaluation followed by local-variable stores and a jump. A jump. A freaking `GOTO` of yore! We'll be wanting that too, more in a sec. +I mean, under the covers, the JVM certainly has no inherent moral objection to overwriting a [local-variable slot](https://docs.oracle.com/javase/specs/jvms/se25/html/jvms-2.html#jvms-2.6.1). Clojure's own compiler even reuses those slots to _implement_ `loop` and `recur`. But I'm not allowed to assign to an ordinary lexical local myself? That heady stuff is only for the elite class of compiler writers, I guess? Is it ungrateful of me, as a mere user, to not be entirely satisfied with the privilege of supplying replacement values to approved recursion points? + +And that gives us a way in. [`recur`](https://clojure.org/reference/special_forms#recur) evaluates its arguments, rebinds the loop locals, and starts the loop body again. In [Clojure's compiler](https://github.com/clojure/clojure/blob/clojure-1.12.6/src/jvm/clojure/lang/Compiler.java#L7156-L7227), that becomes argument evaluation followed by local-variable stores and a jump. A jump. A freaking `GOTO` of yore! We'll be wanting that too, more in a sec. Anyway, those local-variable stores under the hood are the keys to the kingdom. We can write assignments where we want them, then compile them into ordinary Clojure that does the updating for us, via `recur`. We can automate the mental gymnastics we usually perform when translating an imperative algorithm.