Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala's trait mix-in call chain

Tags:

scala

traits

I have this Scala code:

trait Foo {
    def foo()
}

trait M extends Foo {
    abstract override def foo() {println("M"); super.foo()}
}

// interface implementation
class FooImpl1 extends Foo {
    override def foo() {println("Impl")}
}

class FooImpl2 extends FooImpl1 with M

object Main extends App {
    val a = new FooImpl2
    a.foo 
}

When executed, it prints out

M
Impl

What I'm curious is the mechanism behind the trait method. In this case, the foo in trait M is invoked first, and then super.foo() invokes the concrete call of FooImpl1.foo(). What's the logic behind this call chain? Is there any documentation about this behavior?

like image 910
prosseek Avatar asked Aug 21 '15 02:08

prosseek


People also ask

What is trait mixing in Scala?

In scala, trait mixins means you can extend any number of traits with a class or abstract class. You can extend only traits or combination of traits and class or traits and abstract class. It is necessary to maintain order of mixins otherwise compiler throws an error.

What is stackable traits pattern in Scala?

The stackable traits design pattern is based on mixin composition—something we became familiar with in the early chapters of this book. We usually have an abstract class or a trait that defines an interface, a base implementation, and traits that extend the abstract class to stack modifications on it.

Can we extend multiple traits in Scala?

A Scala class can extend multiple traits at once, but JVM classes can extend only one parent class. The Scala compiler solves this by creating "copies of each trait to form a tall, single-column hierarchy of the class and traits", a process known as linearization.

What is trait in spark?

A trait encapsulates method and field definitions, which can then be reused by mixing them into classes. Unlike class inheritance, in which each class must inherit from just one superclass, a class can mix in any number of traits.


1 Answers

Yes, it is called "linearization" and it solves the hated Diamond Problem of Multiple Inherithance in a ver clever way.

Check the links (or the original paper and you'll learn more than any a quick answer I can give, but the basic idea is this: The order in which you inherit from multiple traits or abstract classes matters. Scala will create a single inheritance line, with no breaks, by picking parents in order and calling the closest override available.

Or better yet, check the canonical example from Chapter 12 of Programming in Scala, First Edition:


The main properties of Scala's linearization are illustrated by the following example: Say you have a class Cat, which inherits from a superclass Animal and two traits Furry and FourLegged. FourLegged extends in turn another trait HasLegs:

 class Animal 
  trait Furry extends Animal
  trait HasLegs extends Animal
  trait FourLegged extends HasLegs
  class Cat extends Animal with Furry with FourLegged

Class Cat's inheritance hierarchy and linearization are shown in Figure 12.1. Inheritance is indicated using traditional UML notation:3 arrows with white, triangular arrowheads indicate inheritance, with the arrowhead pointing to the supertype. The arrows with darkened, non-triangular arrowheads depict linearization. The darkened arrowheads point in the direction in which super calls will be resolved.

image images/linearization.jpg

Figure 12.1 - Inheritance hierarchy and linearization of class Cat.

The linearization of Cat is computed from back to front as follows. The last part of the linearization of Cat is the linearization of its superclass, Animal. This linearization is copied over without any changes. (The linearization of each of these types is shown in Table 12.1 here.) Because Animal doesn't explicitly extend a superclass or mix in any supertraits, it by default extends AnyRef, which extends Any. Animal's linearization, therefore, looks like:

image images/AnimalLine.jpg

The second to last part is the linearization of the first mixin, trait Furry, but all classes that are already in the linearization of Animal are left out now, so that each class appears only once in Cat's linearization. The result is:

image images/FurryLine.jpg

This is preceded by the linearization of FourLegged, where again any classes that have already been copied in the linearizations of the superclass or the first mixin are left out:

image images/FourLeggedLine.jpg

Finally, the first class in the linearization of Cat is Cat itself:

image images/CatLine.jpg

When any of these classes and traits invokes a method via super, the implementation invoked will be the first implementation to its right in the linearization.

like image 79
Daniel Langdon Avatar answered Oct 13 '22 03:10

Daniel Langdon