Clojure

contains? broken for transient collections

Details

  • Type: Defect Defect
  • Status: Open Open
  • Priority: Critical Critical
  • Resolution: Unresolved
  • Affects Version/s: Release 1.2
  • Fix Version/s: Release 1.8
  • Component/s: None
  • Labels:
  • Patch:
    Code and Test
  • Approval:
    Vetted

Description

Behavior with Clojure 1.6.0:

user=> (contains? (transient {:x "fine"}) :x)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentArrayMap$TransientArrayMap  clojure.lang.RT.contains (RT.java:724)
;; expected: true

user=> (contains? (transient (hash-map :x "fine")) :x)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentHashMap$TransientHashMap  clojure.lang.RT.contains (RT.java:724)
;; expected: true

user=> (contains? (transient [1 2 3]) 0)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentVector$TransientVector  clojure.lang.RT.contains (RT.java:724)
;; expected: true

user=> (contains? (transient #{:x}) :x)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentHashSet$TransientHashSet  clojure.lang.RT.contains (RT.java:724)
;; expected: true

user=> (:x (transient #{:x}))
nil
;; expected: :x

user=> (get (transient #{:x}) :x)
nil
;; expected: :x

Cause: This is caused by expectations in clojure.lang.RT regarding the type of collections for some methods, e.g. contains() and getFrom(). Checking for contains looks to see if the instance passed in is Associative (a subinterface of PersistentCollection), or IPersistentSet.

Approach: Expand the types that RT.getFrom(), RT.contains(), and RT.find() can handle to cover the additional transient interfaces.

Alternative: Other older patches (prob best exemplified by clj-700-8.diff) restructure the collections type hierarchy. That is a much bigger change than the one taken here but is perhaps a better long-term path. That patch refactors several of the Clojure interfaces so that logic abstract from the issue of immutability is pulled out to a general interface (e.g. ISet, IAssociative), but preserves the contract specified (e.g. Associatives only return Associatives when calling assoc()). With more general interfaces in place the contains() and getFrom() methods were then altered to conditionally use the general interfaces which are agnostic of persistence vs. transience.

Patch: clj-700-9.patch

  1. 0001-Refactor-of-some-of-the-clojure-.java-code-to-fix-CL.patch
    07/Jan/11 2:07 PM
    10 kB
    Alexander Redington
  2. clj-700.diff
    25/Mar/11 4:18 PM
    10 kB
    Alexander Redington
  3. clj-700-7.diff
    08/Nov/13 10:14 AM
    11 kB
    Andy Fingerhut
  4. clj-700-8.diff
    01/Sep/14 3:59 AM
    11 kB
    Andy Fingerhut
  5. clj-700-9.patch
    04/May/15 5:10 PM
    4 kB
    Alex Miller
  6. clj-700-patch4.txt
    08/Jun/12 12:44 PM
    11 kB
    Stuart Halloway
  7. clj-700-patch6.txt
    19/Aug/12 4:47 AM
    11 kB
    Andy Fingerhut
  8. clj-700-rt.patch
    17/Dec/14 3:12 PM
    4 kB
    Alex Miller

Activity

People

Vote (17)
Watch (7)

Dates

  • Created:
    Updated: