I’ve recently encountered the following type inference issue using Kotlin 1.2.71 - I just wanted to double check my analysis of the problem.
A simplified version of the problem code is shown below:
abstract class Base
interface MyInterface
class TypeA: Base(), MyInterface
class TypeB: Base(), MyInterface
fun useBase(thing: Base) {}
fun createAndUse(useA: Boolean) {
val thing = if (useA) {
TypeA()
} else {
TypeB()
}
useBase(thing)
}
The error occurs when trying to use thing, and the message is “Type mismatch: inferred type is Any but Base was expected”.
I think this is happening because the type that is chosen is the ancestor of TypeA, TypeB, Base and MyInterface, and the only choice that satisfies all of these is Any. Kotlin cannot in this case choose something like Base & MyInterface, as there is no concept of this type.
The fix (remaining on 1.2.71) is to specify explicitly that thing is of type Base. Would future versions of Kotlin address this?
I have the same problem, i.e., Type inference fails in the above setting.
The problem seems to persist in 1.3.50 (haven’t checked 1.3.41 specifically though).
The online compiler at version 1.3.50 can’t infer the type “Base” for “thing” in the example given by the OP above: https://pl.kotl.in/RDNGEzUvt
I my case this means I either have to annotate a large number of code locations with redundant casts, or avoid this use of interfaces.
So, I’d like to renew the question: Will the kotlin compiler be able to make this type inference in the future? Or is there a fundamental limitation of the type system that inhibits that?
I don’t think compiler will be ever able to handle this. There is no dual type definition in Java, so there won’t be in Kotlin. Your best bet is to simply write thing: Base = ...
This works fine if you remove MyInterface or make Base implement MyInterface instead. The problem is simply that the compiler can’t decide if the variable should be of type Base or MyInterface or something else and the intersection/union type logic isn’t good enough here.
The problem is that the exact type inference algorithm is nowhere specified, as far as I can see, so we don’t know if it’s a bug or not. The implementation also changes between Kotlin versions.
I see – one might investigate further – maybe this kind of inference would always come with a significant increase in complexity? – but it’s not high on my priority list right now – I’ll just work around it for now… thanks!