I'm writing my own range
that implements ISeq
. My original implementation for equiv
was just calling seq
on my range and the other list, and comparing using =
:
(defn equals? [this-range other-range]
(= (seq this-range) (seq other-range)))
This seemed fine, but then I ran into some odd behavior:
(= (new-range 5 10)
(range 5 10))
=> true
(= (range 5 10)
(new-range 5 10))
=> false ; Uh oh
Where new-range
is my custom constructor.
To see how LongRange
handles equivalence, I checked its source. It delegates to ASeq
, and ASeq
's equiv
method starts with the lines:
public boolean equiv(Object obj) {
if (!(obj instanceof Sequential) && !(obj instanceof List)) {
return false;
. . .
Since my range doesn't implement Sequential
or List
, this check fails. It doesn't even try to iterate my range to do a value comparison.
What's the reasoning here? Sequential
is just an empty interface. It seems to just exist to "mark" classes as being sequential without requiring any methods.
I could just have my range implement Sequential
to allow the check, but I'm wondering if my equivalence function should include the same check as ASeq
as well. It seems like an unnecessary check though, as seq
will already fail on a bad argument via clojure.lang.RT/seqFrom
.
What is the purpose for the Sequential
check, should I implement Sequential
to appease such methods, and should I do such a check as well in similar methods?
What return value would you like to get from
(= [1 2] #{1 2})
or from
(= '([1 2]) {1 2})
? In both cases, the two collections are indistinguishable after you seq
them (depending on how #{1 2}
gets hashed, anyway). But they clearly are not equal collections: maps and sets behave very differently from lists and vectors. The main thing distinguishing each pair is that one of them is Sequential (intended for use in a sequential manner) and the other is not. That's what this tagging interface is for.
So, yes, you should check Sequential before declaring your sequential object to be equal to some other object: it cannot reasonably be equal to anything non-sequential.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With