4

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
}
RAbraham
  • 5,956
  • 8
  • 45
  • 80
  • where do you want to use an abstract type? Self is abstract in Organism. – Alois Cochard Apr 27 '13 at 21:22
  • BTW, F-Bound polymorphism is imo 90% of the time a code smell, it's really rare that you actually really have to use this pattern. – Alois Cochard Apr 27 '13 at 21:23
  • @AloisCochard: My use case is something similar to the question I asked here. http://stackoverflow.com/questions/16068398/trait-allowing-subtype-in-method-signature. I would be very interested in knowing your design. I can give more use cases if required – RAbraham Apr 27 '13 at 22:14
  • 2
    Same question [as this one](http://stackoverflow.com/questions/14225582/f-bounded-quantification-through-type-member-instead-of-type-parameter) – 0__ Apr 27 '13 at 22:48

1 Answers1

6

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)
        }
}
Owen
  • 38,836
  • 14
  • 95
  • 125