I would like to define a trait which uses the type of the concrete class which extends it as a return type in one of its abstract methods. Is this possible in Scala (2.13)? For example, the following doesn't compile because I can't find a way to bind the ConcreteType:
trait Shape
trait Growable {
def grow() : ConcreteType
}
case class Circle(x : Int, y : Int, size : Int) extends Shape with Growable {
def grow() : Circle = this.copy(size = size + 1)
}
case class Square(x : Int, y : Int, size : Int) extends Shape with Growable {
def grow() : Square = this.copy(size = size + 1)
}
I achieved something close with the following code:
trait Shape
trait Growable[T <: Shape] {
def grow() : T
}
case class Circle(x : Int, y : Int, size : Int) extends Shape with Growable[Circle] {
def grow() : Circle = this.copy(size = size + 1)
}
case class Square(x : Int, y : Int, size : Int) extends Shape with Growable[Square] {
def grow() : Square = this.copy(size = size + 1)
}
Then a user of this code would use it like this:
val circle : Circle = Circle(0, 0, 10).grow()
val square : Square = Square(0, 0, 10).grow()
// or
val shapes : Seq[Shape] = List(circle, square).map(_.grow())
I would like to avoid having to pass in the type via generics, that seems redundant. Any ideas for how to accomplish this?