Re: Why is the method resolution order different from python,common lisp,...?

martin odersky <[email protected]> Sat, 4 Jun 2016 12:41:41 +0200
Newsgroups gmane.comp.lang.scala
Message-ID <CAENVNkYN+4Yg_EzxXba5UOnGAw6wJMBrq4_FzrobEmcHaJ2=Cw@mail.gmail.com>
It is indeed a subtle distinction. I was well aware of the difference
when I designed Scala's linearization. It's true that Scala's
linearization does not satisfy property (2), so it not a "C3
linearization". However, it satisfies another property instead which
is not shared by CL or Python:

 3. The linearization of the superclass of C is always a prefix of the
linearization of C.

In other words, subclassing of *classes* (not traits) does not change
the linearization order as observed by the superclass. This is
important for good code generation in the presence of separate
compilation. Only that way we can compile the linearization order of a
class once, without regard how it is inherited.

So, in a sense Scala has a distinction between classes and traits here
that CL and Python do not have. Classes are guaranteed to have the
same linearization order in all contexts, traits do not (in fact for
traits the observed linearization order can even flip, as you
noticed).

So, it's all a tradeoff in the end. I don't think the linearization
order of Scala will change at this point. And I have not yet come
across someone that reported having hit with the potential problem you
mention in practice. But of course, people might have had the problem
and not reported it.

Cheers

 - Martin

On Sat, Jun 4, 2016 at 10:17 AM, thomas weidner <[email protected]> wrote:
> Hello,
>
> I am just learning Scala, but have experience in several other languages.
> Reading "Programming in Scala 3rd edition", I am a bit confused about trait
> inheritance. Though the author claims trait inheritance are not multiple
> inheritance, he may be right when he has C++ in his mind, but compared to
> languages like Common Lisp or Python trait inheritance in Scala is just
> multiple inheritance in these languages.
>
> Nevertheless, computing the method resolution order (or class precedence
> list) is done differently in Scala. In CL or Python classes are ordered
> using two principles:
>
> every class after it's superclasses (super traits)
> If two classes appear in the same superclass list, their order is this list
> has to be preserved in the final class precedence list.
>
> If these two relations induce a partial order, a linearization of this order
> is used as class precedence list. Scala seems to pursue a different
> approach, In a recursive approach it concatenates the previously constructed
> linearizations of all super classes in order, and just does not add any
> class again, which are already present. While this approach preserves
> property 1 from above, property 2 may be violated, for example:
> class Base
> trait A extends Base
> trait B extends A
> class Test extends Base with B with A
> This results in the order Test, B, A, Base. Note that B actually is after A,
> although A is written after B in the superclass list of Test. Let's compare
> this to the same example in Python (Note that in Python the first superclass
> is the most important not the last one as in Scala):
> class Base:pass
> class A(Base):pass
> class B(A):pass
> class Test(A,B):pass
> Entering this in the Python interpreter yields an exception: Cannot create a
> consistent method resolution order (MRO) for bases A, B. This is expected
> since A has to come before B as A is a superclass of B, but B has to come
> before A as A is after B in the superclass list of Test. This cycle cannot
> be linearized.
>
> In my opinion the Python result is more natural and error safe as the
> superclass order always respects the way I specify it, if this is not
> possible an error occurs. In Scala, on the other hand, if a supertrait does
> something weird, my superclass order can get mixed and become unexpected. If
> I rely on the order some stacked behaviour, my code can become wrong and the
> error is very subtle and hard to track. (Imagine I add behaviour as a trait
> another trait already implements, even worse imagine this changes in some
> library version).
>
> Nevertheless, if my supeclasses can be linearized in the Python sense, the
> obtained order seems to match the order Scala obtains for the same
> hierarchy, but I am not quite sure about this, I would have to prove this on
> paper.
>
> So my question is: Why is Scala more relaxed than Python or Common Lisp
> constructing the class precedence list? Is there a good reason or is it just
> the way someone implemented it once (maybe because he was unaware of the
> issue)? Will this algorithm change to the Python version in the future
> (2.12/13/...)?
>
> Thanks for reading my post,
> Thomas
>
> --
> You received this message because you are subscribed to the Google Groups
> "scala-language" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> For more options, visit https://groups.google.com/d/optout.



-- 

Martin Odersky
EPFL and Lightbend

-- 
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.