juangamnik
08/07/2016, 5:46 PMClass<T>
parameter for an inline method that has a reified type parameter, but a non-inline method which is „annotated“ with the modifier reified
and uses the type T
as if it were an inline method with reified type parameter. Kotlin will generate this to a method with an implicit Class<T>
parameter (which is not visible in Kotlin) and iff T
has no upper bound at all a boolean flag is added which says whether the reified type is an optional/nullable or not (this seems to be a special case for T
without any bound that I wasn’t aware of. This works because an optional has default implementations for toString()
and co., so that it works as expected even if a null is passed).
The Kotlin compiler will/would add an overload to this function without the implicit parameter (a non-inline function), which can be called from Java. It passes the raw type of the upper bound as cls
(and true for the nullable flag) parameter. It’s just to have a nice Java API without exposing the implicit cls
parameter.
So in Kotlin it would look like this (not a very meaningful example):
fun <reified T> foo(): T? {
val str = „Hello“
if (str is T) {
return str
}
else {
return null
}
}
fun test() {
val myStr: String? = foo()
}
So this should print out Hello
. Let me show the byte code implementation the Kotlin compiler should compile from this, but since IMHO byte code is not so readable I will use semantically equivalent Kotlin code:
// for Java
@Suppress("UNCHECKED_CAST")
fun <T> foo(): T? {
return foo(cls = Any::class.java, nullable = true) as T
}
// the nullable is only necessary iff there is no upper bound
fun <T> foo(cls: Class<T>, nullable: Boolean): T? {
val str = "Hello"
// a nullable check is unnecessary, because `str` can never be `null`
if(cls.isAssignableFrom(str.javaClass)) {
return cls.cast(str)
}
else {
return null
}
}
fun main(args: Array<String>) {
// This is how it is called from "compiled Kotlin".
val myStr: String? = foo(cls = String::class.java, nullable = false)
// This is how Java would call it...
val myStr2: Any? = foo()
println(myStr)
println(myStr2)
}
So with my proposal Kotlins compiler can check what you are doing with the reified type, which is not possible if you pass the class object as a default parameter, because then you are doing reflection in Kotlin instead of let Kotlins compiler check and handle this.