There is an abstract class Animal
. Animal
is extended by Dog
and Cow
. Animal
has an abstract function copy
. When called on Dog
is should return Dog
and when called on Cow
- Cow
.
abstract class Animal[T] {
def copy[CT <: Animal[T]] (): CT
}
class Dog[T] extends Animal[T] {
def copy = new Dog[T]()
}
This gives an error. What am I doing wrong?
Your copy
method in Dog
does not have the same signature as the copy
method in Animal
( Animal
has a type parameter and Dog
does not), so the Scala compiler thinks you haven't implemented it for Dog
. It looks like you're trying to work around the fact that copy
should return the sub-type. You can use a self-type for this:
abstract class Animal[T] { self: T =>
def copy: T = this
}
class Dog extends Animal[Dog]
Unless you had something else in mind for the type parameter?
It might also be more prudent to use F-bounded polymorphism in this case, to verify that T
is a sub-type of Animal
.
abstract class Animal[T <: Animal[T]]
Essentially CT
must be invariant for your approach to work. Your concrete implementation of Dog has no control over the type of CT
, for example it's impossible to account for this with your approach (hence the compiler error):
new Dog[Int]().copy[Cow[Int]]()
Your concrete implementation gives me a Dog
but I wanted a Cow
. This is because your copy
method cannot possibly satisfy the return type parameter variance. If all you need is one return type for the copy
method you could employ this alternative (inspired by the same problem as it occurs in C++):
abstract class Animal[T, SubType <: Animal[T, _]] {
def copy (): SubType
}
class Dog[T] extends Animal[T, Dog[T]] {
override def copy() = new Dog[T]
}
val animal: Animal[Int, Dog[Int]] = new Dog()
val dogCopy: Dog[Int] = animal.copy()
Here's another simpler (not as obvious) approach. Scala permits you to override not just the implementation of a method, but also the return type to some degree:
abstract class Animal[T] {
def copy (): Animal[T]
}
class Dog[T] extends Animal[T] {
override def copy() = new Dog[T]
}
val dog = new Dog[Int]()
val dogCopy: Dog[Int] = dog.copy()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.