Transitional data type operations do not guarantee that they will return the same link as those that were passed. Sometimes an implementation may decide to return a new (but still transitional) card after assoc! instead of using the one you went through.
ClojureDocs page on assoc! has a good example that explains this behavior:
I would like to repeat this last part because it is very important: the original collection that you passed in should be considered as having undefined value. Only the return value is predictable.
Here's a modified version of your code that works as expected:
(count (let [m (transient {})] (persistent! (reduce (fn [acc i] (assoc! acc ii)) m (range 1000000)))))
As a side note, the reason you always get 8 is that Clojure likes to use clojure.lang.PersistentArrayMap (a map supported by an array) for cards with 8 or less elements. Once you finish 8, it will switch to clojure.lang.PersistentHashMap .
user=> (type '{1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a}) clojure.lang.PersistentArrayMap user=> (type '{1 a 2 a 3 a 4 a 5 a 6 a 7 a 8 a 9 a}) clojure.lang.PersistentHashMap
After you go through 8 entries, your transition card will switch the backup data structure from an array of pairs ( PersistentArrayMap ) to a hash table ( PersistentHashMap ), after which assoc! returns a new link instead of just updating the old one.
Daowen
source share