I’ve found a case where type-inference “hides” a c...
# announcements
a
I’ve found a case where type-inference “hides” a compile-time error and turns it into a runtime problem. I have this snippet:
Copy code
class Holder<out T>(val make: () -> T)
fun <T> Holder<T>.test(value: T) = check(value == make())

fun main() {
    val h: Holder<Int> = Holder { 10 }
    h.test("what?") // intuitively, should not compile
}
I would expect that this code does not type-check, because I am trying to compare
Int
and
String
. However, in the call to
test
,
T
is inferred to
Any
. Which actually allows you to pass any argument whatsoever, and it will compile. The problem is that
Holder
class is a library class, that I cannot modify. However, the
test
function I can modify, but without changing its signature. Is there a way to make the
test
function check that
T
is actually the same at the call-site without explicit typing? (
h.test<Int>("what?")
) P.S. Removing
out
modifier from the
Holder
signature solves the problem, but unfortunately, the
Holder
class comes from a dependency.
m
So since the
out
is there, `Holder<int> isa `Holder<Any>`Since
Holder<Any>
contains an extension function that can take a
String
everything works. This shouldn't cause any problems. Since T can only be used as an
out
anything that
test
does with the
T
will be limited to
Any?
so the type inference choice should not cause any runtime problems. It might be nice for this to be broken, but I think this behavior is what is desired most of the time.
a
You are right about the is-a relation with
Holder<Any>
. I guess not much harm is done, because as soon as you try to use the type inferred to
Any
, you start getting compile-time errors. E.g. if
test
would return
value
.