Details
-
Type:
Defect
-
Status:
Open
-
Priority:
Major
-
Resolution: Unresolved
-
Affects Version/s: Release 1.3, Release 1.4, Release 1.5
-
Fix Version/s: Release 1.5, Release 1.6
-
Component/s: None
-
Labels:None
-
Environment:Clojure 1.3 om Mac OS 10.7, Clojure 1.5.0 alpha1 on Linux x86_64 (OpenJDK 1.7.0 b147)
-
Patch:Code and Test
-
Approval:Screened
Description
I (Stu) agree with Nicola's assessment in the comments: the single real problem here is that the compiler's MapExpr parser emits maps differently from other map-makers, e.g. RT's factory functions.
Patch clj944-plus-tests does three things:
- has the compiler emit map types consistent with the reader (like the previous "0002" patch)
- adds tests
- removes broken tests
Original report follows:
Hi guys, I am getting the following exception:
(.containsKey {:one 1} :one)
;=> ClassCastException clojure.lang.PersistentArrayMap cannot be cast to clojure.lang.PersistentHashMap
The map is a clojure.lang.PersistentArrayMap, which obviously has a containsKey method (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentArrayMap.java#L95).
Casting it works fine though:
(.containsKey ^clojure.lang.PersistentArrayMap {:one 1} :one)
;=> true
The mailing list suggest that the compiler injects an incorrect cast to clojure.lang.PersistentHashMap. In this case it should probably be cast to a clojure.lang.Associative, the highest common interface having the .containsKey method.
The problem is not present in Clojure 1.2.1.
I don't think that there are two issues here.
The issue is only one: the compiler doesn't emit maps in a way consistent with what the reader returns and with how the compiler itself uses maps.
The symptoms are two: some interop calls fail, and def'ed vars with a literal map as value never use a PersistentArrayMap.
The underlying cause of those two symtoms is fixed by the patch 002 that i submitted (incorporated in Stu's clj944-plus-tests patch.
Stuart said that this approach feels fragile but the bug is caused by the fact that everywhere else clojure returns a PersistentArrayMap when the element count is <= than the PersistentHashMap threshold, and when emitting maps, it doesn't.
Making clojure emit maps consistently with how clojure does internally everywhere else looks to me like the only solution, and I don't really see how making clojure consistent is a fragile approach.
But again, if somebody can suggest a better solution to this problem, I'll gladly submit another patch.