Scala: how to refer to the type of an extending class in a superclass?

Tag: scala , types Author: wq0606 Date: 2014-01-26

Is there a way to define a type T in Parent such that T will always become the actual type of the extending class (in this case Child)?

In Parent, I want to enforce/declare T to be always the extending type, as if I would have written type T="type_of_the_extending_class" in each actual extending class without actually writing down the lines type T=Child1 in Child1 etc.

So Child1's method only should accept Child1 objects as parameter and Child2's method should only accept Child2 objects. Is there a simpler way to enforce this? Is there a way without writing type T=ChildX in each ChildX class ? Is there a way without this boilerplate?

I've been searching for a solution in Scala books but did not find any.

abstract class Parent{
  type T<:Parent
  def method(t:T) 

class Child1 extends Parent{
  type T=Child1
  override def method(t:T)=t.child1method
  def child1method=println("child1's method")

class Child2 extends Parent{
  type T=Child2
  override def method(t:T)=t.child2method
  def child2method=println("child2's method")
Have you tried "this.type"?
@stefan.schwetschke That is the correct solution. You should add it is an answer
Actually this.type probably isn't the correct solution—see my answer below.
Travis Brown is correct. this.type is to restrictive. Two instances of the same sub class have different a this.type.

Best Answer

The standard solution to this problem is F-bounded polymorphism (which isn't Scala-specific—you'll find it used in Java, etc.):

trait Parent[T <: Parent[T]] {
  def method(t: T)

class Child1 extends Parent[Child1] {
  def method(t: Child1) = println("child1's method")

class Child2 extends Parent[Child2] {
  def method(t: Child2) = println("child1's method")

As a side note, there's been some grumbling about F-bounded polymorphism in the Scala community—Kris Nuttycombe for example says it's "tricky to get right and causes typing clutter in the codebase", and I've personally found that I use it less and less often after several years of writing Scala. When your program architecture leads you to need this kind of inheritance, though, it's exactly the right tool for the job.

The problem with this.type (mentioned in the comments) is that it won't allow you to do most of the things you'd reasonably want to do—it's too specific:

scala> abstract class Parent {
     |   def method(t: this.type)
     | }
defined class Parent

scala> class Child1 extends Parent {
     |   def method(t: this.type) = println("child1's method")
     | }
defined class Child1

scala> val a = new Child1
a: Child1 = [email protected]

scala> val b = new Child1
b: Child1 = [email protected]

scala> a.method(b)
<console>:12: error: type mismatch;
 found   : b.type (with underlying type Child1)
 required: a.type

The only argument we can pass to a.method is a itself.