Trait allowing subtype in method signature
generics, scala, types
Solution
It's common to use something called F-bounded polymorphism (see Scala School).
trait Organism[Self <: Organism[Self]] { self: Self =>
def reproduceWith(org:Self):Boolean
}
class Amoeba extends Organism[Amoeba] {
def reproduceWith(org:Amoeba) = ???
}
class Dinosaur extends Organism[Dinosaur] {
def reproduceWith(org:Dinosaur) = ???
}
class Monster extends Dinosaur
`Organism[X]` where `X` states that it must be an `Organism[X]`. This means that only an `X` can be passed in that also extends `Organism[X]`.
To prevent `Dinosaur extends Organism[Amoeba]` I have added a self type `self: Self =>` that tells the compiler this trait should be mixed in with the type that was passed in.
The `mate` function now looks like this:
def mate[Species <: Organism[Species]](male:Species, female:Species) =
male reproduceWith female
Usage is like this:
val a1 = new Amoeba
val a2 = new Amoeba
val d1 = new Dinosaur
val d2 = new Monster
mate(a1, a2)
mate(d1, d2)
// wont compile
// mate(a1, d1)
If you want even more restriction on the types (and with that more complex code) you can take a look at this answer: Scala: implementing method with return type of concrete instance
Problem
How do I enforce subtype in a method defined in the inherited trait? What do I place in the ??? below ``` trait Organism { def reproduce(org:???):Bool } class Amoeba extends Organism { def reproduce(org:Amoeba) = {// so cute..} } class Dinosaur extends Organism { def reproduce(org:Dinosaur) = { // so scary} } ``` My Client Code will be something like: ``` object BoozeParty { def gonuts() = { val (maleOrganism:Organism,femaleOrganism:Organism) = getOrganisms() maleOrganism.reproduce(femaleOrganism) } } ``` The above code should work irrespective of me sending dinosaurs or amoebas via the method getOrganisms() as it returns a tuple of (Organism,Organism) The two concepts that I want to achieve are: - Amoeba knows how to mate with Amoeba and Dinosaur knows how to mate with Dinosaur. So let them figure out the intricate details. - A dinosaur should not be passed to an amoeba. Only an amoeba to an amoeba