The second one is the example that surprised me, but I don't think I'd ever trying mixing in a type that's already a superclass.
Anyway, it surprises me because the mixin declaration is supposed to get priority when method names overlap. I'm wondering if the compiler ignores the "with T" because T is already a parent type.
In the third example, we see this - the ET trait gets priority because it's the furthest to the right in the instantiation.
In the fourth example, the ET trait can only be mixed in with a class that extends T now because ET declared that it extends T. Since C extends T, it's safe to do a mixin of C with ET.
The override abstract/super.f combo works and this kind of strategy is usually meant for stacking abilities. The super call isn't so much a "parent" call like it is in
Java, but instead hands off control to the next class or mixin trait in line... the next to the left in declaration of the instantiation. In your example, C with ET, ET's super hands off to C because C is the next to the left in the declaration.
You could try to explore this with:
val x = new C with T with ET
but it's consistent with example 2, where T will pretty much get ignored and super.f will jump over to C.
But trying:
val x = new C with EET with ET
with a definition of:
gives the result:
In EET.f
In ET.f
In C.f
3
That really baked my noodle. According to the rule... ET.f should have run first. But maybe this is like your second example where the extended trait (in this case ET) gets ignored. But it
didn't get ignored completely. Now, does ET.f show up because the EET's super call had ET as the next in priority line... or was this an actual case of super calling the parent (the traditional meaning) rather than passing along to the next in line?
Well, if C is now changed to extend EET, the output only gives the output for C.
Or, if instead I make EET extend T instead of ET
trait ET extends T ...
trait EET extends T ...
class C extends T ...
val x = new C with EET with ET...
... I get the output:
In ET.f
In EET.f
In C.f
3
So here's my theory:
The rightmost gets priority
unless the rightmost already is a parent or ancestor of either the class or another mixed in trait.
If that rightmost trait calls super, the trait looks through its parent structure. If its closest parent has the same method, that parent's method is called
unless that parent is already a parent of the (leftmost) class. If the trait who called super does not find a match in one of its parents that isn't also a parent of the (leftmost) class, then the "next in line" (next one to the left) gets priority to answer the super call.
Repeat as necessary.
[ July 13, 2008: Message edited by: Marc Peabody ]