jeudi 2 juillet 2015

How do you mixin functionality to each step of an iterative procedure with Scala?

I am working on an optimization procedure in Scala and am looking for advice on how to structure my problem. The procedure takes one step at a time, so I've naively modelled the problem using a Step class:

class Step(val state:State) {
  def doSomething = ...
  def doSomethingElse = ...
  def next:Step = ... // produces the next step in the procedure
}

Each step in the procedure is represented by the immutable Step class whose constructor is given the state produced by the previous step and whose next method produces a subsequent Step instance. The basic idea is then to wrap this with Iterator[Step] so steps can be taken until the optimization converges. Although a bit simplistic, this works well for the vanilla case.

Now, however, I need to add various extensions to the algorithm, and I need to arbitrarily mixin these extensions depending on the problem being optimized. Normally this would be accomplished with the stackable trait pattern but this approach poses a couple of issues for this problem. Here is an example of a would-be extension:

trait SpecialStep extends Step {
  // Extension-specific state passed from step to step
  val specialState:SpecialState = ...

  // Wrap base methods to extend functionality
  abstract override def doSomething = { ...; super.doSomething(); ... }
}

The main issue is that the next method of the base class doesn't know which extensions have been mixed in, so subsequently produced steps will not incorporate any extensions mixed into the initial one.

Also, each extension may need to pass its own state from step to step. In this example a SpecialState instance is included in the mixin, but without overriding the next method, SpecialStep has no way to pass along it's SpecialState, and overriding next cannot be done since there may be multiple extensions mixed in, each only aware of itself.

So it seems I've painted myself into a corner here and am hoping someone has some insight for how to approach this with Scala. Which design pattern is most appropriate for this type of problem?

Aucun commentaire:

Enregistrer un commentaire