clojure.lang.MapEntry violates .equals and .hashCode contracts of HashMap.Entry; leads to non-reflexive .equals, etc.

Description

user> (let [h (HashMap.)]
(.put h 1 2)
(let [p1 (first h)
p2 (first {1 2})]
(println (.hashCode p1) (.hashCode p2)
(= p1 p2) (= p2 p1)
(.equals p1 p2) (.equals p2 p1))))

3 994 false false true false

clojure.lang.MapEntry does not follow the contracts of hashCode or equals for java.util.Map$Entry. This, among other things, leads to the above non-reflexive behavior of .equals.

I realize this isn't a simple bug; it's a fundamental issue, in that it's impossible to consistently implement both java.util.List and java.util.Map$Entry, which clojure.lang.MapEntry claims to do. On balance I do find it very useful that Clojure map entries are equivalent to vectors, and probably wouldn't want to give that up. But, I think that at minimum this wart should be documented somewhere, since it could lead to some very strange and hard to catch bugs.

Environment

None

Activity

Show:
Rich Hickey
July 29, 2011, 1:45 PM

doc patch ok

Stuart Halloway
March 5, 2011, 3:11 AM

Rich: is there a doc patch you would want for this?

Jason Wolfe
March 3, 2011, 4:13 AM

This might be fixable by changing seq to promise a sequence of pairs rather than MapEntries. I don't know enough about Clojure internals to know if this would entail too large a performance hit, but perhaps it's worth considering.

Assignee

Unassigned

Reporter

Jason Wolfe

Labels

None

Approval

None

Patch

None

Affects versions

Priority

Minor