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

0 votes
ago in Collections by
;; merge
(merge {:a :b} [:a :c]) ;=> {:a :c}

;; merge-with
(merge-with (fn [_ x] x) {} {:a :b} [:a :c])
;; => class clojure.lang.Keyword cannot be cast to class java.util.Map$Entry

I think this happens because merge-with eventually calls seq on the "Map", expecting to get a "Map Entry" from which then it can extracts key and value, and fails when receiving a Vector, because seq will just yield one element at a time:

(key (first (seq {:a :c}))) ;; => :a
(key (first (seq [:a :c])))
;; => class clojure.lang.Keyword cannot be cast to class java.util.Map$Entry

I think it is justified to expect that (partial merge-with (fn [_ x] x)) should behave exactly as merge and my proposal is to make it happen, if what I described makes sense.

Thank you!

1 Answer

+1 vote
ago by
selected ago by
 
Best answer

merge and merge-with are both explicit in their docstring about being defined on maps, and merge-with leverages that assumption in its implementation (seq'ing a map should yield map entries). There is no stated behavior for non-map arguments to merge or merge-with, and thus the behavior here is undefined and should not be relied upon.

conj on maps is defined for vector entries and that yields the behavior in the merge case, but I see that as implementation details, not advertised and expected.

...