Reputation: 6324
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:
Upvotes: 4
Views: 1969
Reputation: 11244
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
Upvotes: 10