~ / track D / fp foundations

Immutability

Basic

In Clojure, the built-in collections are persistent: every "update" returns a brand new value and leaves the original untouched. You don't mutate data; you derive new versions of it. That sounds expensive, but Clojure shares structure between versions, so the cost is small and the guarantees are huge.

Minimal example

conj returns a new vector with one more element. The original is unchanged when you look at it again:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

The same holds for maps. assoc produces a new map; the original still has the old value:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

Practical example

Because values do not change behind your back, you can hold onto a snapshot and trust it. Here a "transaction history" keeps every prior state:

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate

This is why local reasoning works in Clojure: if you bound xs ten lines ago, nothing your callees do can make xs mean something else now.

Exercise

Define rename-key, which takes a map m, an old key k, and a new key k', and returns a new map with the value moved from k to k'. The original m must not change.

loading sci
press ⌘/Ctrl-↵ or click ▶ run to evaluate
 status: new