clojureequality

Unexpected equality semantics of Java byte arrays in Clojure


I'm trying to check equality between two byte arrays: I'm running the following code:

;; Test 1
(= (byte-array [0 0 0 0])
   (byte-array [0 0 0 0])) ;; => false

;; Test 2
(= (seq (byte-array [0 0 0 0]))
   (seq (byte-array [0 0 0 0]))) ;; => true

Test 1 fails, but test 2 passes. Is this defined behavior? Do I need to file a bug report?

I was expecting the equality operator to pass on both of these assertions.


Solution

  • If you look at Clojure’s Equality Guide, the first sentence in the Summary section answers this question:

    Clojure’s = is true when comparing immutable values that represent the same value, or when comparing mutable objects that are the identical object.

    Because Java arrays (which are what byte-array returns) are mutable objects, and you are passing two different arrays in the first assertion, the failure is expected.

    In the second assertion, by the time = has walked the lazy sequences returned by seq, they are both immutable sequences with the same values in each, so the assertion passes as expected.

    There’s a lot of valuable information on that equality guide, so it’s worth studying. And it’s also good to remember that in Clojure you are best sticking to immutable values, not things like Java arrays, if you want to reason about your code. That’s where the big wins come.