Tom G
Tom G

Reputation: 2045

Scala: trying to understand Traits, 'abstract override' and stacking

Assuming I have a simple abstract base class like so:

abstract class MyAbstractBaseClass { 
    def hello : Unit 
}

and then I write a "stacking" trait like so:

trait MyTrait extends MyAbstractBaseClass { 
    abstract override def hello : Unit = 
    { 
        super.hello             
        println("How are you?"); 
    }
}

then why won't Scala let me define a subclass as follows:

class MyClass extends MyAbstractBaseClass with MyTrait {
    override def hello : Unit = println("Hello!")
}

error: overriding method hello in trait MyTrait of type => Unit;
 method hello needs `abstract override' modifiers

If I try their suggestion of using 'abstract override':

class MyClass extends MyAbstractBaseClass with MyTrait {
    abstract override def hello : Unit = println("Hello!")
}

error: `abstract override' modifier only allowed for members of traits

Can anyone help me understand this?

P.S. I know that the below does work:

class MyClass extends MyAbstractBaseClass {
   override def hello : Unit = println("Hello!")
}

val x = new MyClass with MyTrait
x.hello

Hello!
How are you?

but am trying to understand why the former does not.

In summary: why can't I provide an implementation of the abstract base class - while also taking advantage of the trait's functionality?

Upvotes: 1

Views: 1388

Answers (1)

Mik378
Mik378

Reputation: 22171

The trick is that you can't have an "abstract" method in the flow of the linearization, that is called from a super call.

Try this, you will see it compiles:

abstract class MyAbstractBaseClass {
  def hello : Unit
}

class SubClass extends MyAbstractBaseClass {
  def hello {
    println("toto")
  }
}


trait MyTrait extends MyAbstractBaseClass {
  abstract override def hello : Unit =
  {
    super.hello
    println("How are you?")
  }
}

class MyClass extends SubClass with MyTrait {  //note the CONCRETE SubClass here
  override def hello : Unit = println("Hello!")
}

new MyClass().hello

You got the error, because the compiler starts with MyTrait (at the top of the stack, so the first to be called) and that MyTrait calls through super an abstract method... (of MyAbstractBaseClass) => it crashes since your super call can't target immediately a concrete method.

In my code snippet, you will notice that MyTrait is "at the top" (during linearization) of a concrete Subclass class, that makes the trick.

Upvotes: 2

Related Questions