I have an immutable Set of a class, Set[MyClass], and I want to use the Set methods intersect and diff, but I want them to test for equality using my custom equals method, rather than default object equality test
I have tried overriding the == operator, but it isn't being used.
Thanks in advance.
Edit:
The intersect method is a concrete value member of GenSetLike
spec: http://www.scala-lang.org/api/current/scala/collection/GenSetLike.html src: https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/GenSetLike.scala#L1
def intersect(that: GenSet[A]): Repr = this filter that
so the intersection is done using the filter method.
Yet another Edit:
filter is defined in TraversableLike
spec: http://www.scala-lang.org/api/current/scala/collection/TraversableLike.html
def filter(p: A => Boolean): Repr = {
val b = newBuilder
for (x <- this)
if (p(x)) b += x
b.result
}
What's unclear to me is what it uses when invoked without a predicate, p. That's not an implicit parameter.
You'll need to override
.hashCode
as well. This is almost always the case when you override.equals
, as.hashCode
is often used as a cheaper pre-check for.equals
; any two objects which are equal must have identical hash codes. I'm guessing you're using objects whose defaulthashCode
does not respect this property with respect to your custom equality, and the Set implementation is making assumptions based on the hash codes (and so never even calling your equality operation).See the Scala docs for
Any.equals
andAny.hashCode
: http://www.scala-lang.org/api/rc/scala/Any.htmlequals and hashCode are provided automatically in case class only if you do not define them.
If what you want is reference equality, still write equals and hashCode, to prevent automatic generation, and call the version from AnyRef
With that:
You cannot override the
==(o: Any)
from AnyRef, which is sealed and always calls equals. If you tried defining a new (overloaded)==(m: MyClass)
, it is not the one thatSet
calls, so it is useless here and quite dangerous in general.As for the call to
filter
, the reason it works is thatSet[A]
is aFunction[A, Boolean]
. And yes,equals
is used, you will see that function implementation (apply
) is a synonymous forcontains
, and most implementations ofSet
use==
in contains (SortedSet
uses theOrdering
instead). And==
callsequals
.Note: the implementation of my first
equals
is quick and dirty and probably bad if MyClass is to be subclassed . If so, you should at the very least check type equality (this.getClass == that.getClass
) or better define acanEqual
method (you may read this blog by Daniel Sobral)"It is not possible to override == directly, as it is defined as a final method in class Any. That is, Scala treats == as if were defined as follows in class Any:
" from Programming In Scala, Second Edition
This answer shows a custom mutable Set with user-defined Equality. It could be made immutable by replacing the internal store with a
Vector
and returning a modified copy of itself upon each operation