Multiple invariant parameters leads to type compilation failure?

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>) {
fun <T: Animal>petBoth(secondBoundedInvariant: SecondBoundedInvariant<T>, invariant: BoundedInvariant<T>) {

val animalSet = mapOf(
    BoundedInvariant(Dog()) to SecondBoundedInvariant(Dog()),
    BoundedInvariant(Cat()) to SecondBoundedInvariant(Cat()),

fun main() {
        .forEach {
            //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)?


In this case it.value and it.key are of type out Animal but your function expects Animal type. Just change your function parameter declaration like this:

fun <T: Animal>petBoth(secondBoundedInvariant: SecondBoundedInvariant<out T>, invariant: BoundedInvariant<out T>) {

Or you can change the declaration of invariant data classes:

data class BoundedInvariant<out T: Animal>(val thing: T)
data class SecondBoundedInvariant<out T: Animal>(val thing: T)
1 Like

I think Peter is right,
With its definition of BoundedInvariant & SecondBoundedInvariant classes (without covariant ‘out’ word)

The code

Should not compile


I would guess that the reason it compiles is because the compiler infers the following type arguments:
Container<Animal>(BoundedInvariant<Animal>(Dog()), SecondBoundedInvariant<Animal>(Cat()))