Are Kotlin's reified types incorrect for primitives on the JVM?
Asked Answered
I

1

9

If a Kotlin function invocation reifies a primitive, say Int, the 'passed' class is that for the boxed primitive, not the unboxed version.

inline fun <reified T> reify() = T::class

@Test fun reified_type_doesnt_match_for_primitive() {
    assertNotEquals(Int::class, reify<Int>())
    assertNotEquals(Int::class.java, reify<Int>().java)
    assertNotEquals<Any>(Int::class, reify<Int?>())

    val nullableInt: Int? = 42
    assertNotEquals(nullableInt!!.javaClass.kotlin, reify<Int>())

    assertEquals<Any>(java.lang.Integer::class.java, reify<Int>().java)
}

@Test fun reified_type_matches_for_class() {
    assertEquals(String::class, reify<String>())
}

Is this a bug?

Irrecoverable answered 29/11, 2015 at 20:33 Comment(0)
N
9

This is somewhat confusing, but the current behavior is by design. This approach has a major benefit compared to the one where we would treat T::class.java as a primitive class. If the function has a parameter of type T, its Java class is always equal to T::class.java at runtime (assuming T is final). This is actually a very sensible thing to expect:

    inline fun <reified T : Any> foo(t: T) {
        assert(T::class.java == t.javaClass)
    }

This happens because the parameter of a generic type T can only have a reference value at runtime, which is necessarily a boxed value if T is a primitive type.

Also see a thread on the Kotlin forum on this subject: https://devnet.jetbrains.com/thread/475540

Nedanedda answered 30/11, 2015 at 1:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.