Overriding subclass methods with subclassed arguments?

inheritance, overriding, scala

Solution

abstract class Animal[T <: Animal[T]] {
  def mateWith(that: T)
}

class Cow extends Animal[Cow] {
  override def mateWith(that: Cow) { println("cow") }
}

class Dog extends Animal[Dog] {
  override def mateWith(that: Dog) { println("dog") }
}

And use it like this:

scala> (new Cow).mateWith(new Cow)
cow

scala> (new Cow).mateWith(new Dog)
<console>:17: error: type mismatch;
 found   : Dog
 required: Cow
              (new Cow).mateWith(new Dog)
                                 ^

No exception-throwing code needed; the type system handles it for you at compile-time!

Problem

How can I force base methods to take in the same specific subclass instance when overriden by a subclass? i.e.: ``` abstract class Animal { def mateWith(that: Animal) } class Cow extends Animal { override def mateWith...? } ``` Logically, a `Cow` should only be able to `mateWith` another `Cow`. However, if I do `override def mateWith(that: Cow)`, this doesn't actually override the base class method (which I want it to, since I want to enforce its existence in the subclass). I could check to make sure the other instance is of type Cow, and throw an exception if it isn't - is this my best option? What if I have more animals? I would have to repeat the exception-throwing code.

Original source