Intent-Driven Design
How Stone trades low-level control for clarity of intent — and why that makes programs faster, not slower.
Optimisation techniques are mature and well-studied. Constant propagation, loop-invariant code motion, dead code elimination, vectorisation — compilers have known how to do these for decades. The bottleneck was never the compiler's ability to optimise. It was the compiler's ability to understand.
Most performance languages respond by giving programmers more control over the machine — manual memory management, explicit lifetimes, inline assembly. Stone takes the opposite approach: instead of more control, more clarity. The programmer's job is to explain what they mean. The compiler's job is to make it fast.
Consider a GPS. It already knows every road, every traffic pattern, every shortcut in the city. You don't give it turn-by-turn directions — that would be slower and less reliable than what the system can work out on its own. Your job is to be precise about where you want to go. Say "somewhere near downtown" and the GPS can't help you. Say "142 Oak Street" and it finds the optimal route instantly.
Programming languages have faced the same choice. Traditional performance languages are like giving turn-by-turn directions — you control every detail, but the system can't improve on your route because it doesn't know your destination. Stone is like giving a clear address. The compiler already knows how to optimise. It just needs to know what you meant.
Two Tracks
Language design has historically split into two tracks: fast or readable. Each generation picked a side.
Maximum control. Raw pointers, manual memory, direct machine access.
Controlled control. Ownership and lifetimes constrain what the programmer can do.
Transparent control. Comptime and explicit allocators make every decision visible.
Fast, but the programmer carries the complexity.
Readability first. Clean syntax, dynamic typing, minimal boilerplate.
Simplicity as policy. Small language, fast compilation, easy to read and learn.
Bridges the gap. Clean syntax with C-level speed via JIT, but performance requires discipline.
Clear, but performance requires extra effort or runtime trade-offs.
Intent-driven design dissolves the trade-off. The programmer writes clear, readable code — no manual memory management, no lifetime annotations, no runtime overhead. The compiler extracts performance from that clarity. Fast and readable, not fast or readable.
The key insight: if a programmer can optimise it, a compiler can too — more reliably and more consistently. Compilers don't get tired, don't forget edge cases, and can apply dozens of optimisation passes in sequence. What they need is not more power, but more clear information.
Stone's language rules aren't restrictions. They're requirements for precision. Each one forces the programmer to express intent unambiguously — and each one directly enables a category of compiler optimisation.
Rules as Communication
Each rule closes a specific gap between what the programmer meant and what the compiler sees. These aren't safety features — they're communication features.
No Rebinding
x = 5 # ... 200 lines later ... x = x + 1
The programmer meant two different things — a constant and an updated value — but used the same name for both. The compiler sees a and has to track which version of x is current at every point in the program.
x = 5 y = x + 1
x = 5 is a fact, not a moment in time. The compiler can propagate it, inline it, reorder around it, eliminate it — because there is no ambiguity about what x is. The programmer was forced to name the new value, which is what they actually meant anyway.
Explicit State Mutation
while (i < n) {
sum += arr[i];
i++;
}The compiler sees mutable variables being written. It has to figure out the programmer's intent: which variable is the ? Which is the accumulator? What's the update pattern? It has to work backwards from the code to understand the structure.
evolve { sum = 0, i = 0 } while (i < n) {
sum' = sum + arr[i]
i' = i + 1
}The programmer declared: here are my state variables, here are their starting values, here are their update rules. The compiler sees a with explicit transitions — no guesswork needed.
No Shadowing
const x = 5;
if (condition) {
const x = 10;
use(x); // which x?
}The programmer may or may not have intended to hide the outer value. The compiler has to track scope chains. The reader has to mentally resolve which binding each reference points to.
x = 5
if (condition) {
inner_x = 10
use(inner_x)
}Every name refers to exactly one thing, everywhere in its scope. When you see x, it's that x — no disambiguation needed.
The Pattern
| Rule | What it forces | What it eliminates |
|---|---|---|
| No rebinding | Name different values differently | "Which version?" |
| Explicit state (primes) | Declare state transitions explicitly | "What changed?" |
| No shadowing | One name = one thing | "Which one?" |
Traditional languages give you a mutable variable and say "do whatever you want." That's control. Stone says "tell me what you mean." That's intent. And intent is what the compiler needs to optimise well.
The Compound Effect
These rules don't operate in isolation. They compound:
- 1No rebinding makes every value a permanent fact, so the compiler can propagate constants through the entire program.
- 2Explicit state tells the compiler exactly where values change and how, so it can classify loop patterns and replace them with closed-form math.
- 3No shadowing ensures that propagated constants and classified patterns are never invalidated by a name collision in a nested scope.
Together, they create a language where the compiler sees everything the programmer intended — and nothing they didn't. That's why Stone programs written at a high level of abstraction compile to code that matches hand-optimised C.
See How Stone Is Fast for the full technical breakdown of the optimisations these design choices enable.
Stone doesn't give you more control. It gives you more clarity. And clarity is all the compiler ever needed.