F4.05 · part 3 of 3
Structural sharing
The trie nodes are immutable, so an insert cannot edit them in place. Instead it builds new nodes only along the path from the root to the changed leaf, and reuses every other sub-tree exactly as it was. The result is a second map that shares almost all of its structure with the first — and the first map is still there, unchanged.
Adding one page to the registry, "PGE0NcQgyPQEbI", turning version
v1 into v2. Select what to highlight.
Advanced: persistence and snapshots
Because each insert keeps the old map intact and shares all but one path, a sequence of edits is a sequence of versions that overlap almost entirely. A history of a hundred edits does not cost a hundred copies of the map; it costs a hundred short paths, with every untouched sub-tree shared across all of them. That is the meaning of a persistent data structure: old versions stay valid and cheap, so holding a snapshot is nearly free.
For the portal’s page registry — read on every request, edited when a page is added — that
is the property that matters: a new registry shares its structure with the one before it, so a LiveView can
diff two snapshots by comparing references and skip the shared sub-trees entirely. F4.06 (CHAMP) keeps this
sharing and adds a canonical shape, which makes those snapshot comparisons cheaper still; the
stack’s BrandedChamp trie (F4.07) is that structure, keyed by branded Snowflake
ids.
# v1 holds three pages; adding one returns v2 — v1 is untouched v1 = %{"PGE0NXh7MFjxT6" => modules, "PGE0NbLeJJpTmr" => sorting, "PGE0NbWMtkolM0" => maps} v2 = Map.put(v1, "PGE0NcQgyPQEbI", trees) # only the nodes on the path to the new leaf are rebuilt # v2's other sub-trees are the same references as v1's — shared, not copied v1["PGE0NbWMtkolM0"] == v2["PGE0NbWMtkolM0"] # true; v1 still works
F4.05.3 · path-copy sharing
An insert copies one path and shares the rest; old versions survive.
F4.06 · a canonical shape
CHAMP keeps the sharing and gives the tree one shape per map, so diffs are cheaper.
That completes F4.05: a HAMT packs each node with a bitmap, indexes by five-bit chunks of the hash, and shares structure on every insert. Next module: F4.06 — CHAMP maps, the compressed successor that splits the node into two bitmaps and two arrays — the next step of the persistent-map spine.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Bagwell, P. (2001). Ideal Hash Trees. — the original HAMT paper, where path-copy sharing on insert is set out.
- Hash array mapped trie — Wikipedia — the structure in brief.
Related in this course
- F4.05 · Hash Array Mapped Tries (HAMT)
- F4.04 · Maps, sets & hashing
- F4.06 · CHAMP maps — the compressed successor that keeps this sharing.