HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Removing asInstance[T] from scala code

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
removingscalaasinstancecodefrom

Problem

I've written this scala code and I cannot work out how/if it is possible to remove the asInstance in the definition of class Problem.

The basic idea is that there are two hierarchies

Problem
SpecificProblem
ConcreteSpecificProblem


and

SolutionFinder
SpecificSolutionFinder
ConcreteSpecificSolutionFinder


These hierarchies will branched in the future, but at the moment there is only one concrete class and its direct parents.

SolutionFinder classes operate on Problem classes, and on construction of a Problem we provide a SolutionFinder instance that we will operate on it. The type declaration of the Problem class/subclasses specifies which SolutionFinder subclass be used on it, and the SolutionFinder type declaration specifies which Problem classes it be applied to.

The aim is to be able to just call solve on any kind of Problem and have it use the appropriate methods.

As it stands, the code works fine for all the examples I have tried.

I think that it is correct to say in the type declaration of Problem, it is implicit (in the non-scala-keyword sense) that S = S[S,T] = Problem[S,T]. The compiler does not recognise this, perhaps because I'm wrong about this and perhaps because this level of recursive type definition is beyond it's capabilities. To get around this I have told it to convert this to an S using asInstance, which is a faux-pas which I would like to avoid.

So, is there a better way of doing it. Should I be prepared for unforeseen consequences?

`object test {

abstract class SolutionFinder[T

Solution

There is no implicit inference that S = S[S,T] = Problem[S,T]. But you can add an explicit one:

abstract class Problem[T 
    def solve(): Unit = solutionFinder.findSolution(this)
}


A better design might be to disentangle the Problem and Solution. Perhaps the solve could be moved out of Problem, and require the Solution only at the point of use?

trait Problem
trait Solution[P <: Problem] {def solve(p: P): Unit }
class ConcreteProblem extends Problem
class ConcreteSolution extends Solution[ConcreteProblem]
def solve[P <: Problem](p: P, s: Solution[P]) = s.solve(p)


If you need a more sophisticated relation between Problem and Solution, you could create a typeclass for the "relationship", with implicit instances available:

trait KnowsHowToSolve[P <: Problem, S <: Solution] {
  def solve(p: P, s: S): Unit
}
implicit object ConcreteProblemKnowsHowToSolveConcreteSolution extends KnowsHowToSolve[ConcreteProblem, ConcreteSolution] {
  def solve(p: ConcreteProblem, s: ConcreteSolution) = s.findSpecificSolution(p)
}
def solve[P <: Problem, S <: Solution](p: P, s: S)(implicit ks: P KnowsHowToSolve S) = ...

Code Snippets

abstract class Problem[T <: SolutionFinder[S, T], S <: Problem[T, S]](solutionFinder: T) {
  this: S =>
    def solve(): Unit = solutionFinder.findSolution(this)
}
trait Problem
trait Solution[P <: Problem] {def solve(p: P): Unit }
class ConcreteProblem extends Problem
class ConcreteSolution extends Solution[ConcreteProblem]
def solve[P <: Problem](p: P, s: Solution[P]) = s.solve(p)
trait KnowsHowToSolve[P <: Problem, S <: Solution] {
  def solve(p: P, s: S): Unit
}
implicit object ConcreteProblemKnowsHowToSolveConcreteSolution extends KnowsHowToSolve[ConcreteProblem, ConcreteSolution] {
  def solve(p: ConcreteProblem, s: ConcreteSolution) = s.findSpecificSolution(p)
}
def solve[P <: Problem, S <: Solution](p: P, s: S)(implicit ks: P KnowsHowToSolve S) = ...

Context

StackExchange Code Review Q#66852, answer score: 3

Revisions (0)

No revisions yet.