https://kotlinlang.org logo
Title
r

robin

09/19/2018, 6:08 PM
Facing a weird case here, I have the following function:
fun <T> test(param: T) {
    val clazz = param::class
}
And the compiler complains (rightly so) that param has a nullable type 'T'. It even suggests using
!!
to make it non-nullable, but if I do that, the compiler still complains with the exact same message. Here are a few more variations I've tried, each one with the same error message:
val clazz = param!!::class
val clazz = param?.let { it::class }
val clazz = if (param != null) param::class else null
So, how am I supposed to get to the class of
param
here? Is this a bug with type inference or am I missing something? Making
T
reified or constrain it to
Any
is not an option.
Okay, safe-casting to
Any
inside the function works:
val clazz = (param as? Any)?.let { it::class }
But that seems... Unneccessarily convoluted.
s

Shawn

09/19/2018, 6:24 PM
why can’t you constrain it to Any?
r

robin

09/19/2018, 6:25 PM
Because the function I'm actually doing this in is overriding a function from an interface I have no control over.
k

karelpeeters

09/19/2018, 6:33 PM
I definitely think this is a bug: extensions functions do in fact work fine:
fun Any.foo() = print(this.toString())

fun <T> bar(param: T) {
    if (param != null) {
        println(param.foo())
        println(param::class)
    }
}
Only the
:class
line has an error here. Changing the parameter type to
Any?
also fixes the issue. Can you report this on YouTrack?
r

robin

09/19/2018, 6:35 PM
Yes, will do!
k

karelpeeters

09/19/2018, 6:35 PM
Looks like someone got there before you did: https://youtrack.jetbrains.net/issue/KT-20778
r

robin

09/19/2018, 6:36 PM
Ah right, thank you! And it's already 11 months old...
Added my workaround there for completeness.
k

karelpeeters

09/19/2018, 6:41 PM
(x as Any?)?.let { it::class }
works too and doesn't do the useless
INSTANCEOF java/lang/Object
check at runtime 😒imple_smile:
r

robin

09/19/2018, 6:42 PM
Yeah that's better, didn't even think about that 😄
d

Dico

09/19/2018, 7:58 PM
Um, I have no clue what
param!!::class
does. Aren't you looking for
param.javaClass
? Just requires it to be non-null. Well, just add a constraint
<T : Any>
k

karelpeeters

09/19/2018, 7:59 PM
As discussed that's not an option, and this is definitely a bug.
Casting
T
to
Any?
shouldn't affect whether null checks work, see my minimal code example.
r

robin

09/19/2018, 7:59 PM
Yup, not an option, although I think
param?.javaClass
might work in my case, but won't work if you actually need the KClass.
d

Dico

09/19/2018, 8:00 PM
Yeah, I agree that what I just tested is behaving unlike what I would expect.
r

robin

09/19/2018, 8:00 PM
param!!::class
is just asserting
param
to be non-null, and then getting it's
KClass
. At least that's what it should do.
d

Dico

09/19/2018, 8:00 PM
Oh right, ::class can give you the
KClass
of the object
You can try
?.javaClass?.kotlin
for now
But yeah, weird thing is that a non-null assertion of a generic type parameter with default upper bound
Any?
is not considered to be a subtype of
Any
k

karelpeeters

09/19/2018, 8:02 PM
It is, see my code 😛. It just doesn't work for
::class
for some reason.
d

Dico

09/19/2018, 8:03 PM
Alright, I guess
::class
is a special case then.
k

karelpeeters

09/19/2018, 8:04 PM
Must be, I'm looking around in the source.
Maybe that's called before smart casting etc is done? I don't have a debugging environment for the compiler set up unfortunately.