Cornelius
Cornelius

Reputation: 660

Why is it not possible (in scala) to provide implementation for an abstract override method in the implementing base class

What I would like to do is this:

trait Addable[T]{
  def plus(x: T): T
}

trait AddableWithBounds[T] extends Addable[T] {
  abstract override def plus(x: T): T = limitToBounds(super.plus(x))

  def limitToBounds(x: T): T = ... //Some bounds checking
}

class Impl(num: Int) extends AddableWithBounds[Impl] {
  override def plus(x: Impl) = new Impl(num + x.num)
}

Reading through various posts it would seem that the reason this is not possible is that after class linearization the stacked trait is only looking in classes to its right for implementations of super.plus(x: T)

That is a technical argument though and I'm interested in the question: Is there a fundamental reason why the implementation could not be taken from the base class? Because as you can see in this example it is not possible to implement the plus method before knowing the actual data type that needs to be added but afaic implementing bounds checking in a trait seems reasonable.

Just as an idea: If the problem is that in this case it is unclear which plus is being overridden in the base class maybe a scope identifier like

def Addable[Impl].plus(x: Impl) = new Impl(num + x.num)

would help.

Upvotes: 2

Views: 140

Answers (2)

som-snytt
som-snytt

Reputation: 39577

You're asking: if super.f is abstract (or "incomplete") after mixin, please just pick a concrete f to serve. Maybe you're saying, only if there's exactly one such f, and it's defined in the current template.

One problem is that if the abstract f is called during initialization, and calls the concrete f in the subclass, the initializer for the subclass hasn't run yet.

This is common gotcha for template methods. I think the Josh Bloch book says don't do that.

But the person writing the stackable trait has no way of knowing that a super was transformed in this way.

Upvotes: 1

0__
0__

Reputation: 67280

I would avoid overriding and reliance on some super/sub-type invocation. Why not just implement plus and ask sub-types to provide an auxiliary abstract method:

trait Addable[T] {
  def plus(x: T): T
}

trait AddableWithBounds[T] extends Addable[T] {
  final def plus(x: T): T = limitToBounds(plusImpl(x))

  protected def plusImpl(x: T): T

  def limitToBounds(x: T): T = ??? //Some bounds checking
}

class Impl(num: Int) extends AnyRef with AddableWithBounds[Impl] {
  protected def plusImpl(x: Impl): Impl = ???
}

Upvotes: 2

Related Questions