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)?