Derivation
In the immutable view, view,} nothing ever changes. Instead, new things come into being.
When a player moves a piece, we don't modify the board. We create a new board---one that reflects the move. The old board still exists, unchanged, frozen in time like a photograph.
This may sound wasteful, even absurd. Why create something new when you could simply update what's there?
But consider: every photograph you've ever taken still exists. Taking a new photo doesn't destroy the old ones. Your photo library is a history---each image a frozen moment, all coexisting.
The Act of Derivation
In the immutable view, we don't change. We derive. We describe what the new state should be in terms of the old.
| Natural Language | Notation |
|---|---|
| Derive new board from the current one | new_state = state with {...} |
| The knight moves from g1 to f3 | board with {g1: empty, f3: knight} |
The notation X with {changes} means: "Take X, and give me something just like it, except with these changes applied." The original X is untouched.
The Photograph Analogy
Imagine photographing the chess board after every move.
Click. The starting position. Click. After white's first move. Click. After black's response. Click. Click. Click.
Now you have a stack of photographs. Each one is complete---a full snapshot of the board at that moment. None of them change. They simply are.
When someone asks "what did the board look like after move 15?" you don't need to remember. You pull out photograph 15.
This is the immutable view. States don't transform. New states are derived, and old states persist.
A Chess Move in the Immutable World
Let's trace the same move: white's knight from g1 to f3.
We start with state_0---the current state of the game.
state_0: The Original
state_0:
board: g1 has knight, f3 is empty
turn: whiteThe Derivation
Now the move happens. But we don't modify state_0. We derive state_1 by expressing the differences:
state_1 = state_0 with {
board: state_0.board with {
g1: empty, // difference 1
f3: white knight // difference 2
},
turn: black // difference 3
}Three differences---the same three we saw before:
- g1 is empty (was: knight)
- f3 has the knight (was: empty)
- turn is black (was: white)
But here's the key insight: we don't change anything. We describe what's different. The notation with {...} means "like this, except for these differences."
There is no temporary variable to hold the knight. There is no sequence where we must clear before placing. There is just a complete description of how state_1 relates to state_0.
Two States Coexist
After the derivation, both states exist:
Both are complete. Neither has changed. state_0 still shows the knight at g1---it always will.
The Relationship Between States
In the immutable view, we think not of a single state that changes, but of relationships between states.
state_0 state_1
The arrow is a function---a relationship that says "given this state and this move, the result is that state." The function doesn't do anything to state_0. It merely describes what state_1 would be.
We can write this as:
move(state, from, to) =
state with {
board: state.board with {
[from]: empty,
[to]: state.board[from]
},
turn: opposite(state.turn)
}This is a pure function. It takes a state and a move, and it returns a new state. It does not modify its inputs.
What We Gain
The immutable approach offers:
- History
- — Every state ever computed still exists. The past is not lost.
- Safety
- — No one can modify what you're looking at. It's frozen.
- Certainty
- — When you say "state_0," you mean exactly one thing, forever.
- Reasoning
- — Functions are predictable. Same input, same output, always.
These advantages compound. When nothing changes, you can reason about your program with mathematical certainty. There are no surprises from hidden modifications.
What We Lose
But something is lost:
- Memory
- — Multiple states coexist. This uses more space.
- Familiarity
- — This is not how physical objects work. It requires a mental shift.
- Simplicity
- — We must think about which state we mean.
The immutable world is foreign at first. We are used to objects that change. But the rewards---history, safety, certainty---are profound.
A Different Flow of Time
In the immutable view, time doesn't flow. It branches.
state_0 state_1 state_2 …
But unlike the mutable view, all these states coexist. We can revisit state_0 at any time. We can ask "what if we had moved differently?" and explore an alternate branch.
Time becomes a tree of possibilities, not a line of destruction.
Try It Yourself
Try It Yourself
9 exercises to practice
We have now seen two philosophies. In the next chapter, we step back and ask: which serves us better, and when?