This definition: class TypeTest[+U]
means that, e.g., a TypeTest[Integer]
is a valid substitute for a TypeTest[Number]
. Therefore, as per the Liskov substitution principle, anything a TypeTest[Number]
can do, a TypeTest[Integer]
must be able to do as well. But this is clearly not the case here: if your code compiled, you could provide any Number
to an instance that expects at least an Integer
.
Although it may be tricky to understand these issues generally, you can trust the compiler on the co-/contravariance issues. It is because it can be quite hard for us to get right that the compiler does these extra checks. But if you really do want to get around the variance check, you can do it nevertheless:
class TypeTest[+U] {
def call(func: Function0[U @uncheckedVariance]): U = func()
}
Example of why using this would be a bad idea
Because this would compile and throw at runtime:
trait Fruit
case class Orange(orangeKind: String) extends Fruit
case class Apple(appleKind: String) extends Fruit
def main(args: Array[String]) {
val testApple = new TypeTest[Apple] {
override def call(func: () => Apple) = func().copy(appleKind = "Different")
}
val testFruit: TypeTest[Fruit] = testApple
testFruit.call(() => Orange("Round"))
}