On the JVM, we have to contend with type erasure. Meaning essentially that the types (T
in this case) are thrown away in the compiled bytecode and that required checks are only done at compile time. Given that, you have to look at your function declaration with that in mind.
Kotlin will define your function argument as a Function0
in both cases. Because the types are erased, () -> Unit
and () -> Foo<T>
both look the same in the bytecode. We can prove this out by decompiling the code you've provided (I renamed one of these myFunction2
to get this to work):
public final class com/ginsberg/KotlinStuffKt {
public final static myFunction(Lcom/ginsberg/Foo;Lkotlin/jvm/functions/Function0;)Lcom/ginsberg/Foo;
public final static myFunction2(Lcom/ginsberg/Foo;Lkotlin/jvm/functions/Function0;)Lcom/ginsberg/Foo;
}
This is what the Kotlin compiler is generating (it does more, but I have removed the non-essential parts from this example). As you can see, our types are gone thanks to type erasure. And if we undo my change (myFunction2
becomes myFunction
), there's no way at all to tell these apart. This is what the compiler is complaining about - if you erase the types the JVM can't tell these functions apart.