Reputation: 177
I thought the following 2 code snapshots would be equivalent, but they produce different results. Can u explain why?
1) Traits added to class declaration:
trait M1 {
override def toString() = "m1"
}
trait M2 {
override def toString() = "m2"
}
class C extends M1 with M2 {
override def toString() = {
s"C and ${super.toString()}"
}
}
val c = new C
c.toString() //C and m2
2) Traits added on the fly:
class C {
override def toString() = {
s"C and ${super.toString()}"
}
}
val c = new C with M1 with M2
c.toString() //m2
Upvotes: 2
Views: 144
Reputation: 11917
The two approaches are not identical.
Version one overrides toString AFTER the mixins have been applied.
The second approach mixes in after C has been created, and thus the toString in M2 overrides the one on C.
Two things of fun are happening here, firstly mixins in Scala are scanned right to left. This is why M2 is called before M1. The second is that new C with M1 with M2 will be creating a synthetic class behind the scenes that extends C. That synthetic class is enhanced to include M2 and M1 and this extension will be overriding the toString method on C. Where as declaring C to extend M1 and M2 directly builds the behaviour directly into the class C and the override method on C kicks in to take precedence.
Upvotes: 3