Welcome! Please see the About page for a little more info on how this works.

0 votes
in Collections by

https://github.com/clojure/clojure/blob/010864f/src/clj/clojure/core.clj#L6553-L6562

Because PHMs implement clojure.lang.IKVReduce and IPersistentMap, they have nondeterministic dispatch through the protocol that backs reduce-kv (clojure.core.protocols/IKVReduce).

A potential way to solve this is to add an instance check for clojure.lang.IKVReduce inside reduce-kv (This is similar to how reduce checks for IReduceInit)

Another approach is to extend the protocol to PersistentHashMap and PersistentArrayMap directly (in addition to preserving the existing extensions)

3 Answers

0 votes
by

Comment made by: bronsa

CLJ-1807 offers a generic solution for this class of problems

0 votes
by
_Comment made by: gshayban_

Repro code


(def C (atom 0))

;; reextend for instrumentation
(extend-protocol clojure.core.protocols/IKVReduce
 ;;slow path default
 clojure.lang.IPersistentMap
 (kv-reduce
   [amap f init]
   (swap! C inc)
   (reduce (fn [ret [k v]] (f ret k v)) init amap)))

(reduce-kv (fn [_ _ _]) nil (array-map 1 2 3 4))
(println "slowpaths" @C)
(reduce-kv (fn [_ _ _]) nil (hash-map 1 2 3 4))
(println "slowpaths" @C)




Repro output

➜  dev /usr/lib/jvm/java-8-openjdk/bin/java -cp $(clojure -Spath) clojure.main kvfastpath.clj
slowpaths 1
slowpaths 2
➜  dev /usr/lib/jvm/java-11-openjdk/bin/java -cp $(clojure -Spath) clojure.main kvfastpath.clj
slowpaths 0
slowpaths 0
0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1879 (reported by gshayban)
...