66

I have a base abstract class (trait). It has an abstract method foo(). It is extended and implemented by several derived classes. I want to create a trait that can be mixed into the derived classes so that it implements foo() and then calls the derived class's foo().

Something like:

trait Foo {
  def foo()
}

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

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

class FooImpl2 extends FooImpl1 with M 

I tried self types and structural types, but I can't get it to work.

Jacek Laskowski
  • 72,696
  • 27
  • 242
  • 420
IttayD
  • 28,271
  • 28
  • 124
  • 178

1 Answers1

102

You were very close. Add the abstract modifier to M.foo, and you have the 'Stackable Trait' pattern: http://www.artima.com/scalazine/articles/stackable_trait_pattern.html

trait Foo {
  def foo()
}

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

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

class FooImpl2 extends FooImpl1 with M
retronym
  • 54,768
  • 12
  • 155
  • 168
  • What if I don't have M? I'm trying to override the method from Foo in the class and have the same error. – Oleg Abrazhaev Mar 21 '18 at 10:58
  • 2
    What does `super.foo()` do when foo is unimplemented in the super class? – lamino Apr 07 '19 at 00:07
  • @lamin The trait `M` needs to be mixed in along with its super class or trait, and if that super class or trait doesn't have `foo` implemented, then it can't be overriden yet, and `super.foo()` won't get called. – lvsz Jan 20 '23 at 21:29