Removing asInstance[T] from scala code 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 &lt;: Problem[S, T], S &lt;: SolutionFinder[T, S]] {
    def findSolution(problem: T): Unit
  }

  abstract class SpecificSolutionFinder[T &lt;: SpecificProblem[S, T], S &lt;: SpecificSolutionFinder[T, S]]
    extends SolutionFinder[T, S] {
    def findSolution(specificProblem: T): Unit = findSpecificSolution(specificProblem)
    def findSpecificSolution(specifProblem:T): Unit
  }

  class ConcreteSpecificSolutionFinder
    extends SpecificSolutionFinder[ConcreteSpecificProblem,ConcreteSpecificSolutionFinder] {
    def findSpecificSolution(specificProblem: ConcreteSpecificProblem): Unit = {
      // Actual solution to problem goes here
    }
  }


  abstract class Problem[T &lt;: SolutionFinder[S, T], S &lt;: Problem[T, S]](solutionFinder: T) {
    def solve(): Unit = solutionFinder.findSolution(this.asInstanceOf[S]) // I WANT TO AVOID THIS
  }

  abstract class SpecificProblem[T &lt;: SpecificSolutionFinder[S, T], S &lt;: SpecificProblem[T, S]](specificSolutionFinder: T)
    extends Problem[T, S](specificSolutionFinder) {
    // Problem specific fields and methods
  }

  class ConcreteSpecificProblem(concreteSpecificSolutionFinder: ConcreteSpecificSolutionFinder)
    extends SpecificProblem[ConcreteSpecificSolutionFinder,ConcreteSpecificProblem](concreteSpecificSolutionFinder) {
    // Problem specific fields and methods with values
  }

  def main(args: Array[String]): Unit ={
    val solutionFinder = new ConcreteSpecificSolutionFinder
    val problem = new ConcreteSpecificProblem(solutionFinder)

    // The aim of the codes structure is to avoid writing
    solutionFinder.findSolution(problem) // (which works, but is not appropriate for how this is used)
    // and write
    problem.solve()
    // instead
  }
}
There is no implicit inference that S = S[S,T] = Problem[S,T]. But you can add an explicit one:

abstract class Problem[T &lt;: SolutionFinder[S, T], S &lt;: Problem[T, S]](solutionFinder: T) {
  this: S =&gt;
    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 &lt;: Problem] {def solve(p: P): Unit }
class ConcreteProblem extends Problem
class ConcreteSolution extends Solution[ConcreteProblem]
def solve[P &lt;: 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 &lt;: Problem, S &lt;: 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 &lt;: Problem, S &lt;: Solution](p: P, s: S)(implicit ks: P KnowsHowToSolve S) = ...