Search code examples
scalatraitsabstract-type

Scala traits and name collision in abstract types


I'm trying define a trait C which extends some traits A,B,... All traits,C and A,B,... implement a common trait T. Trait C is supposed to implement T by calling the implementations of T in A,B,..:

trait T{
  def f()
}
trait A extends T{
  def f(){
    print("A")
  }
}
trait B extends T{
  def f(){
    print("B")
  }
}

The desired behavior of trait C is as follows:

val x=new A with B with C[A,B]{}
x.f()
// should produce output
A
B

Here my attempt to define trait C, which gave compilation errors:

trait C[A<:T,B<:T] extends T{
  self:A with B =>
  override def f(){
    // error: A does not name a parent class of trait C
    super[A].f()
    // error: B does not name a parent class of trait C
    super[B].f()
  }
}

I need to call within C methods A.f() and B.f(). Is there any solution to this?


Solution

  • If you want to provide an implementation inside of a trait but also ensure that subclasses implement the definition, it is possible to tell this the compiler with the abstract override combination:

    trait T {
      def f()
    }
    trait A extends T {
      abstract override def f() {
        super.f()
        print("A")
      }
    }
    trait B extends T {
      abstract override def f() {
        super.f()
        print("B")
      }
    }
    
    trait C extends T {
      override def f() {
        // do your work here ...
      }
    }
    
    val x = new C with A with B
    x.f()
    

    To call the next implementation in the mixin-hierarchy you must add a super.f() call inside of the abstract override method call. Because such a super call requires an existing implementation the first thing you need to create is an instance of C that mixins A and B. If you mixin C in A or B the compiler will complain because the mixin-hierarchy is executed from left to right, thus the implementation of C can not be seen.