Consider the following example:
sealed trait ST
object ST{
case class ST1() extends ST
case class ST2() extends ST
}
trait TypeClass[A]{
def doSome(a: A): Unit
}
case class Test[T](t: T)
implicit val tp: TypeClass[Test[_ <: ST]] = ??? //the implicit
def foo[A: TypeClass](a: A) = implicitly[TypeClass[A]].doSome(a)
val v: Test[_ <: ST] = ???
foo(v) //error: implicit not found
SCASTIE
As can be seen the required implicit is in scope while it is not recognized by the compile.
Why does that happen and is there a workaround to call foo?
If you change foo(v) to foo(v)(tp) it'll explain (a little bit) better why it doesn't want to use tp.
In a nutshell, def foo[A : TypeClass] wants an implicit of type TypeClass[A].
When you do foo(v), A becomes Test[_ <: ST] which means "Test of some specific but unknown subtype of ST". So, foo wants an implicit for that specific type.
But tp is not that. It is a "TypeClass for Test or any subclass of ST" (apparently _ means slightly different things in these two contexts, because v is a concrete instance, that must have a specific type).
Long story short, Test[_ <: ST] is not the actual type of v, but a supertype of its type. So, to make it work, you just need to make the TypeClass contravariant (TypeClass[-A]) - that'll make foo accept tp as the implicit, because its type will be a subtype of what it expects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With