How can I enforce invariance when contravariance is required

Hello,

I have the following simple example that is working:

  case class S[T](a:T)

  sealed trait ParamX[-T]
  final case class C[T](p: T) extends ParamX[T]
  final case class P[T1,T2](p1: ParamX[T1], p2: ParamX[T2]) extends ParamX[(T1,T2)]

  trait SearchX[T <: ParamX[_]] {
    val search: T
  }

  case object A extends SearchX[P[Double,Double]] {
    override val search = P(C(1.0), C(2.0))
  }

  def grid[T](numSamples: Int)(p: ParamX[T]) = S(1.0)

  def checkTest[U <: ParamX[_]](n:Int, t: SearchX[U]): S[Double] = {
    val s1 = t.search
    val s2 = grid(n)(s1)
    s2
  }

  val t1: S[Double] = checkTest(10, A)

Can I change this to make it work with sealed trait ParamX[T]?
If not, can anyone explain why or point me to an explanation?

TIA.

You can make it work if you add an extra type parameter:

case class S[T](a:T)

sealed trait ParamX[T]
final case class C[T](p: T) extends ParamX[T]
final case class P[T1,T2](p1: ParamX[T1], p2: ParamX[T2]) extends ParamX[(T1,T2)]

trait SearchX[A, T <: ParamX[A]] {
  val search: T
}

case object A extends SearchX[(Double, Double), P[Double,Double]] {
  override val search = P(C(1.0), C(2.0))
}

def grid[T](numSamples: Int)(p: ParamX[T]) = S(1.0)

def checkTest[A, U <: ParamX[A]](n:Int, t: SearchX[A, U]): S[Double] = {
  val s1 = t.search
  val s2 = grid(n)(s1)
  s2
}

val t1: S[Double] = checkTest(10, A)

@Jasper-M Once again thank you.

One question though: I understand that “declaring” the type parameter makes it visible and therefore possible to “carry” to other types for binding. I assume that the type parameter A in checkTest will bind to the T in grid. If so, is their any fundamental reason why we have to make this explicit? After all type U has not changed.

TIA

I’m not entirely sure what’s wrong here. Existential types make my head hurt. But I think this is some type inference limitation of the scalac compiler. Dotty seems to be able to compile it as is.

In my case its “heart burn” :slight_smile:. But it is very nice to know Dotty swallows that without a problem (wonder how hard it is going to be to port this to Dotty).

Thank you.