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
src: https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/collection/TraversableLike.scala#L1
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.
equals and hashCode are provided automatically in case class only if you do not define them.
case class MyClass(val name: String) { override def equals(o: Any) = o match { case that: MyClass => that.name.equalsIgnoreCase(this.name) case _ => false } override def hashCode = name.toUpperCase.hashCode } Set(MyClass("xx"), MyClass("XY"), MyClass("xX")) res1: scala.collection.immutable.Set[MyClass] = Set(MyClass(xx), MyClass(XY))
If what you want is reference equality, still write equals and hashCode, to prevent automatic generation, and call the version from AnyRef
override def equals(o: Any) = super.equals(o) override def hashCode = super.hashCode
With that:
Set(MyClass("x"), MyClass("x")) res2: scala.collection.immutable.Set[MyClass] = Set(MyClass(x), MyClass(x))
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 that Set
calls, so it is useless here and quite dangerous in general.
As for the call to filter
, the reason it works is that Set[A]
is a Function[A, Boolean]
. And yes, equals
is used, you will see that function implementation (apply
) is a synonymous for contains
, and most implementations of Set
use ==
in contains (SortedSet
uses the Ordering
instead). And ==
calls equals
.
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 a canEqual
method (you may read this blog by Daniel Sobral)
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