scala: mixins depending on type of arguments

mixins, scala, traits

Solution

Using self types allows you to separate the Model-Algorithm implementations from the instantiations and mix them in:

trait Model
trait Result
trait MCMC extends Model {
  def propose: Result
}
trait Importance extends Model {
  def forward: Result
}

class Normal(val model: Model) extends Model

trait NormalMCMCImpl extends MCMC {
  self: Normal =>
  def propose: Result = { //... impl
    val x = self.model // lookie here... I can use vals from Normal
  }
}
trait NormalImportanceImpl extends Importance {
  self: Normal =>
  def forward: Result = { // ... impl
      ...
  }
}

class NormalMCMC(mean: Model) extends Normal(mean)
                              with NormalMCMCImpl

class NormalImportance(mean: Model) extends Normal(mean)
                                    with NormalImportanceImpl

class NormalImportanceMCMC(mean: Model) extends Normal(mean)
                                        with NormalMCMCImpl
                                        with NormalImportanceImpl

Problem

I have a set of classes of models, and a set of algorithms that can be run on the models. Not all classes of models can perform all algorithms. I want model classes to be able to declare what algorithms they can perform. The algorithms a model can perform may depend on its arguments. Example: Say I have two algorithms, MCMC, and Importance, represented as traits: ``` trait MCMC extends Model { def propose... } trait Importance extends Model { def forward... } ``` I have a model class Normal, which takes a mean argument, which is itself a Model. Now, if mean implements MCMC, I want Normal to implement MCMC, and if mean implements Importance, I want Normal to implement Importance. I can write: class Normal(mean: Model) extends Model { // some common stuff goes here } ``` class NormalMCMC(mean: MCMC) extends Normal(mean) with MCMC { def propose...implementation goes here } class NormalImportance(mean: Importance) extends Normal(mean) with Importance { def forward...implementation goes here } ``` I can create factory methods that make sure the right kind of Normal gets created with a given mean. But the obvious question is, what if mean implements both MCMC and Importance? Then I want Normal to implement both of them too. But I don't want to create a new class that reimplements propose and forward. If NormalMCMC and NormalImportance didn't take arguments, I could make them traits and mix them in. But here I want the mixing in to depend on the type of the argument. Is there a good solution?

Original source