I need a way to enforce a method in an abstract class to have a return type of the concrete class of the object it is called on. The most common example is a copy()
method, and I'm currently using an approach based on abstract types:
abstract class A(id: Int) {
type Self <: A
def copy(newId: Int): Self
}
class B(id: Int, x: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, x)
}
class C(id: Int, y: String, z: String) extends A(id) {
type Self = C
def copy(newId: Int) = new C(newId, y, z)
}
I already saw many approaches, including the ones in this great answer. However, none of them really forces a implementation to return its own type. For example, the following classes would be valid:
class D(id: Int, w: String) extends A(id) {
type Self = A
def copy(newId: Int) = new D(newId, w) // returns an A
}
class E(id: Int, v: String) extends A(id) {
type Self = B
def copy(newId: Int) = new B(newId, "")
}
The fact that I can do that causes that, if I am doing copies of objects of which the only information I have is that they are of a given subclass of A
's:
// type error: Seq[A] is not a Seq[CA]!
def createCopies[CA <: A](seq: Seq[CA]): Seq[CA] = seq.map(_.copy(genNewId()))
Is there a better, type-safe way I can do that?
EDIT: If possible, I would like to keep the ability to create arbitrarily deep hierarchies of abstract classes. That is, in the previous example, I'm expecting to be able to create an abstract class A2
that extends A
, and then proceed to create A2
's concrete subclasses. However, if that simplifies the problem (as it's the case with abstract types), I do not need to further extend already concrete classes.
this.type
case. Why it is not suited for you? – Maysthis.type
is an instance-specific type (i.e. thethis.type
's of two differentA
instances are not the same), and therefore is not suitable for mycopy()
method. – Tiffinfinal
– Mays