8

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?

1
  • 1
    I think the problem here is that what you really want is to say 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! Commented Nov 2, 2012 at 17:43

1 Answer 1

4

After some trial and error, I got it to work. Note: the compiler tells us that type parameters in A[+X] and B[+Y] must be covariant.

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 Test extends App { def emptyList[X[Y <: A[Y]]] = collection.mutable.ListBuffer.empty[X[Y forSome {type Y <: A[Y]} ]] val myList = emptyList[B] myList += E() myList += F() println(myList.map(_.y(2).x)) } 
Sign up to request clarification or add additional context in comments.

1 Comment

I was trying out covariance settings as well, but didn't manage to get the emptyList method correct. Thanks for figuring that out.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.