Home > Enterprise >  How to make a parent class return a type which can match subtypes?
How to make a parent class return a type which can match subtypes?

Time:10-29

How to define return type in a parent class such that it matches child instance class?

In the example below, the echo function needs to be defined such that it returns an object of the child class which calls this.

trait A[T] {
  def echo(a: T): T
}

class B extends A[B] {
  override def echo(x: B):B = x
}

class C extends B {
  def repeat(x: B): B = echo(x)
}

val b = new B()
val c = new C()

// Fails with error value repeat is not a member of B
c.repeat(b).repeat(b) 

// Compilation error
// Found:    B
// Required: D
class D extends B {
  def repeat(x: B): D = echo(x)
}
}

CodePudding user response:

What exactly are you trying to do?

If you trace your call chain, you'll see that c.repeat(b) returns instance of b:B that obviously doesn't have the repeat method, which is defined in C.

In other words, in your code, b.echo(x:B) returns x, not this!

Perhaps you wanted to return this from C.repeat? This should work:

class C extends B {
  def repeat(x: B): C = {
    echo(x)
    this
  }
}

val b = new B()
val c = new C()

c.repeat(b).repeat(b)

CodePudding user response:

As @Aivean mentioned, your method repeat is defined on the class C and returns an instance of its parent class B, which doesn't have the repeat method.

So you cannot call repeat twice like do:

val tmpB = c.repeat(b) // tmpB is an instance of B
tmpB.repeat(b)         // fail cuz B has no "repeat" method

That's that.


Now to answer the main question: "How to make a parent class return a type which can match subtypes?"

Same as you did with trait A, but add constraint on its argument type so that T must be an A:

trait A[T<:A[T]]
class B extends A[B]

Read more about "F-bounded polymorphism" in this great answer: https://stackoverflow.com/a/21699765/1206998

  • Related