The code below generates:
Name’s hashCode
Name’s hashCode
Name’s equals
ID=0
import scala.collection.mutable
object TestTraits {
def main(args: Array[String]): Unit = {
val toto0 = new Person(0,"toto")
val toto1 = new Person(1,"toto")
val peoples = mutable.Set.empty[PersonID]
peoples.add(toto0)
peoples.add(toto1)
peoples.foreach(_.showID)
//peoples.foreach(_.saySomething)//won't compile'
}
}
trait Name{
var theName=""
override def hashCode(): Int = {
println("Name's hashCode")
var hash = 5;
hash = 71 * hash + this.theName.##;
hash
//super.hashCode()//infinite loop
}
override def equals(that: Any): Boolean = {
println("Name's equals")
that match {
case that: Name => this.theName.equals(that.theName)
case _ => false
}
}
}
abstract class PersonID{
val idNumber: Int
override def hashCode(): Int = {
println("PersonID's hashCode")
super.##
}
override def equals(that: Any): Boolean = {
println("PersonID's equals")
that match {
case that: PersonID => this.eq(that)
case _ => false
}
}
def showID: Unit = {
println("ID=" + idNumber)
}
}
class Person(val id:Int, val s:String) extends {
val idNumber=id
} with PersonID with Name {
/*override def hashCode(): Int = {
println("Person's hashCode")
super.## //infinite loop !!
}
override def equals(that: Any): Boolean = {
println("Person's equals")
that match {
case that: Person => this.eq(that)
case _ => false
}
}*/
theName=s
def saySomething: Unit = {
print("Hello, my name is " + theName + ", ")
showID
}
}
Since “peoples” is a set of PersonID, I was expecting the following output:
PersonID’s hashCode
PersonID’s hashCode
ID=0
ID=1
Does someone can explain this behavior and how to do what I expected (that is, to have a class with “equals” based on values of fields except when putting the instance in a Set[PersonID])
Another mystery is why I get infinite loops when I use super.hashCode() in my custom hashCode ?
PS: I use a pre initialized abstract member because I need it in my real use case…
I get this instead:
This happens because
Nameis the last trait in the initialization, so it’s overrides ofhashCodeandequalswill be the first to be called. You wantedSetto call methods based on the static type (ie, what has been declared), which is just not how OO works. If that were true, inheritance and overriding would be all but useless.As for how to accomplish what you want… you can’t. It would be nice if there was a
Setwhich took anEqual[A]type class, but there isn’t. Maybe Scalaz has it.By the way, there’s a call to
super.##which is deemed illegal on Scala 2.9.0.rc2. I’m not sure what that means yet.