liveBook · Manning

Transient data structure

As explained in Clojure: The Essential Reference

A transient map is a temporary mutable map representation that supports efficient batched updates before conversion to a persistent collection.

A transient is a temporary mutable form of a Clojure vector, map, or set. It helps when many updates are needed to construct a collection but callers only need the final persistent result. Create one with `transient`, perform the updates, then convert it with `persistent!`. section 20.1

During the transient phase:

  • Use mutating operations such as `assoc!`, `conj!`, and `dissoc!` instead of their persistent-collection counterparts. Some reads, including `get` and `count`, still work. section 20.1
  • Pass each update’s returned transient to the next update. Repeatedly updating an older reference can produce an incomplete result. section 20.1

Build a map with batched updates

`(let [m (reduce (fn [m k] (assoc! m k k)) (transient {}) (range 20))] (count (persistent! m)))` returns `20`. Here, `reduce` carries each returned transient forward before `persistent!` produces the final map. section 20.1

(import 'java.util.HashMap)

(def transient-map (transient {}))
(def java-map (HashMap.))

(dotimes [i 20] ; #1
  (assoc! transient-map i i)
  (.put java-map i i))

(persistent! transient-map) ; #2
;; {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7}

(into {} java-map) ; #3
;; {0 0, 7 7, 1 1, 4 4, 15 15, 13 13, 6 6,
;;  3 3, 12 12, 2 2, 19 19, 11 11, 9 9, 5 5,
;;  14 14, 16 16, 10 10, 18 18, 8 8, 17 17}

This contrasting example ignores the return value of `assoc!`: after 20 attempted insertions, the resulting persistent map contains only the first eight entries. section 20.1

Keep the mutable phase explicit. A transient is not an `into` destination, and ordinary `conj` does not work on it. For routine collection construction, functions such as `into` and `frequencies` already use transients internally; reach for a transient directly when managing the update loop yourself. section 20.1 section 8.1.1

How Clojure: The Essential Reference covers it

How deep it goes
Works through creation, mutating operations, conversion, and a stale-reference failure without detailing internal implementation.
Examples
Contrasts twenty transient-map updates with a Java `HashMap`, then threads `assoc!` results through `reduce` to retain all entries.
What it assumes
Assumes familiarity with Clojure collections and `reduce` while introducing transient creation, updates, and conversion.
What you can do after
Operate/configure it: create a transient map, carry forward `assoc!` results, and convert it with `persistent!`.
How it connects
Connects transients to persistent collections, `reduce`, `into`, and `frequencies`.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.