3

Given the following example of two traits with one extending another with no implementation of def a in each:

scala> trait A { def a: String }
defined trait A

scala> trait B extends A { abstract override def a: String }
defined trait B

Is the construct useful at all? What are the use cases?

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
  • It's similar to http://stackoverflow.com/q/24792135/1305344 yet mine refers to Scala (not C#). – Jacek Laskowski Mar 01 '15 at 18:56
  • I know that doing `abstract override` is useful with traits when building out a Stackable Behavior setup, but in those cases, there is implementation (the behavior to stack) inside of the `abstract override` defined method. Not sure what the above does w/o any implementation. – cmbaxter Mar 01 '15 at 19:17

3 Answers3

3

I think the answer is essentially the same as the one linked in your comment. In Scala, the abstract keyword for methods isn't required, since the compiler can figure out whether it's abstract or not based on whether or not it has an implementation. So it's usage here is superfluous.

The override keyword is also not required for methods that are implementing an abstract method (or I guess not doing anything at all, in this case). So really, B is equivalent to:

trait B extends A { def a: String }

Or really just (since B will be assumed to be abstract):

trait B extends A

Similarly to the linked answer, I can imagine once scenario where using override might be useful for readability. If I were making the return type of a in B more specific than A, I could use override as a hint that I'm modifying the behavior in some way:

trait A {
    def a: Any
}

trait B extends A {
   override def a: String
}

In this case, I'm hinting that a in B might be slightly different than the inherited signature from A. Of course, this is only useful if it's known to the reader and used in a consistent manner. But I could still do the same thing without the override.

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
3

Short answer: abstract override is not useful in this case. It's basically like giving a type annotation where none would be needed.

The value added use of abstract override is for decorating an implementation that will be mixed in later, sometimes known as the "stackable trait pattern". See Why is "abstract override" required not "override" alone in subtrait?.

Community
  • 1
  • 1
acjay
  • 34,571
  • 6
  • 57
  • 100
2

Abstract override indicates that you wish to override an 'abstract' method. Others address why it's useless here, so I'll focus on an example. Abstract override is best used for mixins. A simple example would be a Pollable trait:

trait Pollable{def poll:Double}

Lets say we want to weight this pollable. This trait will be a mixin for our trait. Our weighted pollable will have a weight field, which it will multiply a poll by to get a result. For example:

class OnePollable extends Pollable{
    def poll:Double=1
}
val myWeightedOne=new OnePollable with WeightedPollable;

Lets try and write this trait:

//Does not compile
trait WeightedPollable extends Pollable{
    var weight=1
    def poll:Double=super.poll*weight
}

If you look, you'll see clearly why this doesn't work. Our trait tries to call a super type method that isn't implemented! One solution is to add a default to the super trait, Pollable:

//Don't do this!
trait Pollable{def poll:Double=1}

This sorta works here, but is sorta dumb in a lot of real world applications. The better way is this:

trait WeightedPollable extends Pollable{
    var weight=1
    abstract override def poll:Double=super.poll*weight
}

It's our friend the abstract override modifier! This tells the compiler that we are overriding an abstract method, but we want to use super to refer to an object we are being mixed into. This also disallows the trait being used as an interface.

Others
  • 2,876
  • 2
  • 30
  • 52