• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Scala mixin behavior

 
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I must admit there are still some pretty basic things about Scala that I don't understand. One of the most basic is the mixin behavior. I guess I originally thought the mixin was only applicable for methods not defined in the class that was being mixed in, obviously that's wrong.

Does exactly what I expect and prints:
In T.f
1


also does what I expect and prints:
In C.f
3

So far so good. Then I try

This is slightly unexpected. I thought i would get:
In C.f
3

But it actually prints:
In ET.f
2

And then for the totally unexpected:


Which I didn't even know would compile, but when it did i expected:
In ET.f
In T.f
1

But it actually printed:
In ET.f
In C.f
3

What are the rules of mixin inheritance in this case?
 
pie sneak
Posts: 4727
Mac VI Editor Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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 ]
 
Garrett Rowe
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the explanation Marc, I'll have to mull this all over with a glass of wine to let it sink in (or a nice mixed drink -- if you'll forgive the pun)
 
Marc Peabody
pie sneak
Posts: 4727
Mac VI Editor Ruby
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When you think you've got it figured out, predict the output of this very tricky one:

reply
    Bookmark Topic Watch Topic
  • New Topic