Reputation: 7438
I expect the following to produce a compilation error, but it doesn't. Any ideas why?
fun <T, U: T> foo(a: T, b: U) {
println("$a $b")
}
foo("bar", 123)
If I call foo()
with explicit type arguments, it fails to compile as expected:
foo<String, Int>("bar", 123)
Error: Kotlin: Type argument is not within its bounds: should be subtype of 'String'
Upvotes: 1
Views: 2019
Reputation: 89558
The compiler tries quite hard to fit the parameters you've provided to a function signature. In this case, it infers the type parameters to be Any
and Int
, so it basically calls the function like this, which of course satisfies the upper bound requirement, because Any
is a supertype of Int
:
foo<Any, Int>("bar", 123)
You can check that this is indeed what's happening in at least two different ways.
You can open intention actions (Alt + Enter on Windows, ⌥↩ on macOS) when your cursor is on the foo
function call and choose Add explicit type arguments
. This will produce the line above.
You can make the function reified
and print the type parameters' classes - these will be the parameters that it knows about at compile time.
inline fun <reified T, reified U: T> foo(a: T, b: U) {
println("$a $b")
println(T::class) // class kotlin.Any
println(U::class) // class kotlin.Int
}
Upvotes: 5
Reputation: 2678
In the first case, the compiler has no idea what type you mean by T
, so it has to guess, and it doesn't necessarily guess the strictest type. One assumption of languages that use type inference is that the programmer meant something correct. String
and Int
are both descendants of type Any
, so the compiler can resolve the first call by substituting Any
in place of T
. Hence, there is no error.
Once you specifically specify types, the compiler has a better idea of what you want, and in that case it is an error. But the first case is correct.
Upvotes: 2
Reputation: 39853
The type inference tries to find a suitable pair. In this case it would be the explicit
foo<Any, Int>("bar", 123)
The compiler knows the relation of T
and U
and thus just needs to find the common super type for String
and Int
for T
.
Upvotes: 4