interface Animal
class Cat: Animal
class Dog: Animal
data class BoundedInvariant<T: Animal>(val thing: T)
data class SecondBoundedInvariant<T: Animal>(val thing: T)
fun <T: Animal>pet(invariant: BoundedInvariant<T>) {
println(invariant.thing::class)
}
fun <T: Animal>petBoth(secondBoundedInvariant: SecondBoundedInvariant<T>, invariant: BoundedInvariant<T>) {
println(invariant.thing::class)
println(secondBoundedInvariant.thing::class)
}
val animalSet = mapOf(
BoundedInvariant(Dog()) to SecondBoundedInvariant(Dog()),
BoundedInvariant(Cat()) to SecondBoundedInvariant(Cat()),
)
fun main() {
animalSet
.forEach {
pet(it.key)
//petBoth(it.value, it.key)
}
}
Why does pet()
compile but petBoth()
does not? It fails with Type mismatch: inferred type is Animal but CapturedType(out Animal) was expected
I understand that petBoth()
parameters are not declared with T as covariant but why does it work in the case of pet()
?
Does it fail in the case of petBoth()
because the compiler cannot prove they are the same T for each iteration of forEach
?
Ok let’s explore that theory a bit further:
data class Container<T: Animal>(val a: BoundedInvariant<T>, val b: SecondBoundedInvariant<T>)
val a = Container(BoundedInvariant(Dog()), SecondBoundedInvariant(Cat()))
This compiles just fine?? This is very unexpected and does not compile in Scala as expected: Scastie - An interactive playground for Scala.
How can the invocation of petBoth()
be fixed without changing those parameters to covariant (undesirable)?