F-Bound Polymorphism with Abstract Types instead of Parameter Types?

generics, scala, types

Solution

There are various ways to do this. Here is one way that I like, that is similar to "parameterized modules" OCaml or Agda.

When you define your `Organism` type, you split it into an abstract type `Organism` and a trait `OrganismOps`. Then you wrap both of these in a trait:

trait OrganismSystem {
    type Organism <: OrganismOps

    trait OrganismOps {
        def reproduceWith(org: Organism): Boolean
    }
}

Because they are wrapped in the same trait, `OrganismOps` can see the `Organism` type.

Now if you want to create a concrete instance of these things, you would do this:

object MyOrganismSystem extends OrganismSystem {
    case class Organism(species: String) extends OrganismOps {
        def reproduceWith(org: Organism) = species == org.species
    }
}

And if you want to define methods that operate generically on organism systems, you would have them take in an `OrganismSystem` as a parameter, or, equivalently, wrap them in a class that takes an `OrganismSystem` as a parameter:

class UsesGenericOrganismSystem(system: OrganismSystem) {
    import system._

    def allCompatible(organisms: Traversable[Organism]): Boolean =
        organisms.toSeq.combinations(2) forall {
            case Seq(o1, o2) => o1.reproduceWith(o2)
        }
}

Problem

How do I convert the following F-Bound Polymorphism to code using Abstract Types? ``` trait Organism[Self <: Organism[Self]] { self: Self => def reproduceWith(org:Self):Boolean } class Amoeba extends Organism[Amoeba] { def reproduceWith(org:Amoeba) = //..code } ```

Original source

Related problems