Why Verse Is Immutable by Default: The Design Philosophy of a Functional Logic Language
Constants first, an explicit set, = as comparison rather than assignment — these Lesson 8 "quirks" aren't style preferences; they're direct products of the language's core. This page shows you Verse's theoretical bedrock: an ICFP 2023 paper, and a calculus called the Verse Calculus.
1. Three "Quirks" That Are Really One Thing
By the end of Lesson 8, you've collected three questions. Why is "immutable" the default, while "mutable" takes a special var? Why must changing a value go through a Set, with not even a lazy shortcut on offer? Why is = a comparison — and why does Verse flatly have no ==? By the habits of most familiar languages, all three run against common sense. But they are really one design decision projected onto three different spots.
That design decision is written up in a formally published paper: The Verse Calculus: A Core Calculus for Deterministic Functional Logic Programming (ICFP 2023), with a star-studded author list — Lennart Augustsson, Joachim Breitner, Koen Claessen, Ranjit Jhala, Simon Peyton Jones (one of the fathers of Haskell), Olin Shivers, and Epic's own Tim Sweeney. The paper gives Verse a mathematical core: a deterministic functional logic calculus. In plain words: at heart, Verse belongs to the "mathematical proof + logical deduction" family of languages, not the familiar "issue commands one after another" kind.
2. Everything Is an Expression; Bindings Are Single-Assignment by Default
In this calculus, there is no such thing as a "statement" — everything is an "expression", and every piece evaluates to a value (or fails to). if evaluates to a value, a whole block of code evaluates to a value, even the thing you thought was an "assignment command" evaluates to a value. And the relationship between a name and a value defaults to binding, not storage: X := 5 really means "tie X and 5 together" — tied once, tied for life. That's where Lesson 8's "constants are the default" comes from.
Which makes the identity of = fall right into place: in the tradition of logic-deduction languages, X = 5 reads "assert that X and 5 are equal". If the assertion holds, this step goes through; if not, it doesn't — and "not going through" is not an error, not a crash, but a perfectly legitimate branch of control flow in Verse (you'll deal with it properly in the chapter on Branch-style checks). So Verse doesn't need ==: its = was always a question, never an overwrite. The real "overwrite" is fenced off as a dangerous operation — you must first add var, then wire in a Set. Mutable state in this language is a clearly priced exception, not a default as pervasive as air.
3. Fail and Roll Back: set Under "Transaction" Protection
The most stunning corollary of this worldview: changing a value can be undone. When a Set happens inside a "check that might not pass" (say, a Branch's condition area) and that check ultimately doesn't pass, Verse rolls the entire change back — like a database transaction: all or nothing, as if it never happened. This ability is tied to the <transacts> effect specifier on functions. An example:
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/Diagnostics }
rollback_demo_device := class(creative_device):
var Gold:int = 100
OnBegin<override>()<suspends>:void =
if:
set Gold = 999
Gold > 1000
then:
Print("Bet won")
Print("Gold: {Gold}")
Blueprint translation: inside the condition area, a Set first changes Gold to 999, then Gold > 1000 is checked — 999 is not greater than 1000, so the check doesn't go through as a whole. That Set just now gets rolled back, and the final Print String outputs Gold: 100, as if nothing ever happened. In other languages, "try a change, restore things if it doesn't work out" means backing up the old value yourself, writing the restore logic yourself, and guaranteeing yourself that every failed fork restores properly; in Verse, the language handles that behavior out of the box.
Now look back at Lesson 8: the mandatory Set isn't just slip-proofing — precisely because every change is explicitly marked out, the compiler can track exactly "which changes happened inside ranges that might not go through", which is what makes rollback automatable; and "immutable by default" leaves most code with no state needing rollback at all, so reasoning about it is as clean as mathematics. The paper lays out step-by-step rewrite derivations for these rules — you can work out the behavior of a Verse program like working through formulas on paper. Want to dig deeper? The paper's PDF is publicly readable — for a game scripting language, a theoretical bedrock like this is quite a luxury.
4. Quick Quiz
Inside the condition area of a Branch (Blueprint's if check), a Set changes Gold to 999, and then the check doesn't go through as a whole. What is Gold in the end?
Sources
Compiled from the Verse Calculus paper and its public materials: The Verse Calculus project page (Simon Peyton Jones) ↗ · Paper PDF (ICFP 2023) ↗ · ACM Digital Library entry ↗