I am trying to create a list of some trait, parameterised by a type using the CRTP, and cannot figure out how to express the type constraints. Here is some sample code that illustrates the problem:
trait A[X] { def x: X } trait B[Y <: A[Y]] { def y(i: Int): Y } case class C(i: Int) extends A[C] { def x = C(i) } case class D(i: Int) extends A[D] { def x = D(i) } case class E() extends B[C] { def y(i: Int) = C(i) } case class F() extends B[D] { def y(i: Int) = D(i) } object Program extends App { def emptyList[X[_ <: Z forSome { type Z <: A[Z] } ]]() = collection.mutable.ListBuffer.empty[X[_]] val myList = emptyList[B]() myList += E() myList += F() println(myList.map(_.y(2).x)) } So here I'm trying to create a list of objects that conform to the B trait. However this code will not compile, and gives the following error:
kinds of the type arguments (B) do not conform to the expected kinds of the type parameters (type X). B's type parameters do not match type X's expected parameters: type Y's bounds >: Nothing <: A[Y] are stricter than type _'s declared bounds >: Nothing <: Z forSome { type Z <: A[Z] } val myList = emptyList[B] ()
To me it seems like _ <: Z forSome { type Z <: A[Z] } is indeed at least as strict as Y <: A[Y] but maybe I'm missing something.
So the question is - what should the constraints be on the emptyList function to correctly handle B?
X[_ <: Z forAll { type Z <: A[Z] } ]- i.e. you want a higher-rank type. I haven't worked out how to achieve this, though!