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

0 votes
in Clojure by

I have two sequences 'a' and 'b'. Both have the same length and their corresponding element compare equal with '='. But if these two sequences are passed to '=', the result is false:

(doseq [[x y] (zip-colls a b)]
  (println (= x y)))

(count a)
(count b)

(= a b)

This is in contradiction with the clojure equality rule:

Clojure’s = is true when called with two collections, if:

Both arguments are sequential (sequences, lists, vectors, queues, or Java collections implementing java.util.List) with = elements in the same order.

I'm comparing two instances of this class: https://github.com/fctorial/parse_struct/blob/master/src/clojure/lang/ROVec.java

1 Answer

0 votes
selected by
Best answer

There's your problem right there

If the object implements equiv, it'll get picked up by =.

For all other types:
Both arguments are the same type defined with deftype.
The type’s equiv method is called and its return value becomes the value of (= x y).
For other types, Java’s x.equals(y) is true.

I'd bet that if you compared = on their seq coercions, you'd find the seqs are =...

(deftype wrapper [xs] 
   (equiv [this that] false) 
   (seq [this] (seq xs)))

user=> (let [xs (wrapper. [1 2 3]) 
             ys (wrapper. [1 2 3])] 
         [(= xs ys) (= (seq xs) (seq ys))])
[false true]
This is awkward. I did search for 'equals' in this file.
Most clojure collections will implement both equiv and equals for clojure persistent collection equivalence and java interop.  They also implement  hasheq for custom hashing.  They have special util functions for these as well (hash-unordered-collection and hash-ordered-collection) that use murmur3 for idiomatic hashing consistent with clojure's existing collections.  There's a lot of stuff on equality that can be tricky.
For way more detail, see https://clojure.org/guides/equality