Hi!
This is my first topic so thanks for having accepted me. Studying Kotlin I wondered why a type reification requires an inlined function. I’ve searched everywhere online but no one has explained this clearly so I am not able to understand. Why the compiler is not able to reify a type parameter without inlining the function first?
This is a problem of the jvm. What happens is that on the jvm itself does not have generic types (this is called type erasure). So at runtime List<Foo> becomes List and List<Bar> also becomes List. Generic information is only available to the compiler, it isn’t available at runtime. This also means that a function call foo<Int>() at runtime is just foo() so you can no longer use the type parameter inside of the function. You can use it to only for stuff that requires the type parameter at compile time, but not at runtime.
fun <T> foo(arg1: T) {
val f = listOf<T>(arg1) // ok, T is only used at compile time
if(f.first is T) // error, this requires T at runtime, so it can't be done
TODO()
}
To reify a type parameter kotlin inlines the type. That way the type is still known at runtime, but this requires the entire function to be inlined. I hope this helps. Let me know if something is still unclear.
Hi @Wasabi375,
thanks for your exhaustive response, I am almost there. So inline is needed to save the type before it is erased by JVM, but it cannot be done directly inside the called function.
Summing up, reified cannot be used without inline because the reification is based on inlining, right?
You might have (rightfully) assumed that reification should be possible in some cases without inlining. But without jvm runtime support, how would the compiler do it? The compiler would need to generate code for every invocation of a generic function. This code generation would come at a very big cost if done automatically for every generic function. This cost is made obvious by requiring reified generic functions to be inline.
It is probably worth noting that there is another option to reified types that works without inline. Most things you can do with a reified type can also be done using a Class instance.
inline fun <reified T>foo(a: Any): Boolean = a is T
fun foo(a: Any, c: Class<*>): Boolean = c.isAssignableFrom(a)
foo("test", String::class.java)
This works using reflection, and is how java solves this problem. However reflection can have bad performance and might not work on every system (normal windows/linux/macos/android should be fine though).