I can't come up with a very good description of this in words, so, please take a look at this example:
trait Base { def foo = "Base" }
trait One extends Base { override def foo = "One <: " + super.foo }
trait Two extends Base { override def foo = "Two <: " + super.foo }
new Base with One with Two {} foo
This prints: Two <: One <: Base
, which is what I expect.
Now, I am trying to add another level, so that overriding traits would not have to call super
explicitly. Like this:
trait Base { def foo = "Base" }
trait Foo extends Base { def bar = foo + " <: " + super.foo }
trait One extends Foo { override def foo = "One" }
trait Two extends Foo { override def foo = "Two" }
new Foo with One with Two {} bar
Here, the last line prints out Two <: Base
So, it looks like in the first example super
means One
, while in the last one it skips One
and goes directly to Base
.
Why is this happening? Shouldn't behavior be the same?
In the 1st case,
new Base with One with Two {} foo
(which is the same asnew One with Two {} foo
), the "trait stack" is pretty obvious. TheTwo
has afoo
which calls thefoo
of its super (One
) which calls thefoo
of its super (Base
).In the 2nd case,
new Foo with One with Two {} bar
(which is the same asnew One with Two {} bar
), the "trait stack" is Base->Foo->One->Two. You callbar
butTwo
has nobar
andOne
has nobar
.Foo
has abar
that calls thefoo
of its super (Base
).UPDATE
Consider this mod as @Dima has proposed.
Yes, this gives the same output as before:
res0: String = Two <: Base
Now
Two
calls thebar
of its super(One
) which calls thebar
of its super (Foo
) which calls thefoo
(notbar
) of its super.All this
bar
activity is separate from thefoo
definitions.Two
never invokes thefoo
of its super so theOne.foo
is never used and cannot be a part of the output.A DIFFERENT APPROACH
Consider the following.
Now try instantiating this in multiple different ways.
In each case
r.id
will be the last trait in the chain andr.mySup
will be the trait that comes before theR
(orB
if nothing is specified before theR
).super.foo
in theFoo
definition meansBase.foo
as that's the superclass ofFoo
, where the definition is.super
is not a magical keyword that means "one superclass up from the final class".Incidentally, you might also want to look into self-types. See What is the difference between self-types and trait subclasses?