Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trait allowing subtype in method signature

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
like image 938
RAbraham Avatar asked Oct 19 '25 13:10

RAbraham


1 Answers

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

like image 53
EECOLOR Avatar answered Oct 22 '25 03:10

EECOLOR



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!