I am not sure if there is a better way of doing this:
trait Animal {
val name: String
val weight: Int
type SubAnimal <: Animal
def updateName(n: String) = returnMe(n, this.weight)
def updateWeight(w: Int) = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): SubAnimal
}
case class Dog(name: String, weight: Int) extends Animal {
type SubAnimal = Dog
override def returnMe(n: String, w: Int): Dog = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal {
type SubAnimal = Cat
override def returnMe(n: String, w: Int): Cat = Cat("Cat: " + name, w)
}
val fido = Dog("Fido", 11)
println( fido )
val fido2 = fido.updateWeight(12)
println( fido2 )
When I run the code I get this output:
$ scala animal.scala
Dog(Fido,11)
Dog(Dog: Fido,12)
I want to return the actual type of the animal in question after the updateName
or updateWeight
has been called (i.e. not Animal
). I know that if I override updateName
and updateWeight
directly, then the correct type will be returned and I do not have to use the abstract type SubAnimal
.
Is there some tricky way of escaping the abstract type for the special case where the value of the abstract type is the same as the subclass?
(This is know as the "MyType" problem).
This should work:
trait Animal[T] {
self:T =>
val name: String
val weight: Int
def updateName(n: String): T = returnMe(n, this.weight)
def updateWeight(w: Int): T = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): T
}
case class Dog(name: String, weight: Int) extends Animal[Dog] {
override def returnMe(n: String, w: Int): Dog = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal[Cat] {
override def returnMe(n: String, w: Int): Cat = Cat("Cat: " + name, w)
}
Something like case class Cat(name: String, weight: Int) extends Animal[Dog]
gets rejected by the compiler. Code stolen adapted from http://oldfashionedsoftware.com/2009/12/10/self-help/
Some recent discussion on this topic... What you're looking for is commonly referred to as "MyType", and the typical Scala/Java encoding for it uses recursive type parameters:
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {
public final int compareTo(E o)
// ...
}
Using type parametrization?
trait Animal[A <: Animal[A]] {
val name: String
val weight: Int
def updateName(n: String) = returnMe(n, this.weight)
def updateWeight(w: Int) = returnMe(this.name, w)
// Abstract protected method
protected def returnMe(n: String, w: Int): A
}
case class Dog(name: String, weight: Int) extends Animal[Dog] {
override def returnMe(n: String, w: Int) = Dog("Dog: " + name, w)
}
case class Cat(name: String, weight: Int) extends Animal[Cat] {
override def returnMe(n: String, w: Int) = Cat("Cat: " + name, w)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With