Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin class equality fails

The following snippet shows the result of testing equality of Kotlin KClass references obtained from different sources. Their string representations are the same. But their java classes are different. Expected that c, c0 and c1 are equal. But for some reason they aren't.

Is there some nuance or it's a bug? If it's not a bug what is the reliable way to test equality of KClasses?

fun main(args: Array<String>) {
    val c = Int::class
    fun test(v0: Any, v1: Any) {
        val c0 = v0.javaClass.kotlin
        val c1 = v1.javaClass.kotlin
        println("c= $c;  c0= $c0;  c1= $c1") // c= class kotlin.Int;  c0= class kotlin.Int;  c1= class kotlin.Int
        println("c= ${c.java};  c0= ${c0.java};  c1= ${c1.java}") // c= int;  c0= class java.lang.Integer;  c1= class java.lang.Integer
        println("c = c0? ${c == c0};  c0 = c1? ${c1 == c0}") // c = c0? false;  c0 = c1? true
    }
    test(11, 22)
}

EDIT:

The workaround is to use KClass.javaObjectType method.

The docs says:

Returns a Java Class instance corresponding to the given KClass instance. In case of primitive types it returns corresponding wrapper classes.

I.e. c.javaObjectType == c1.javaObjectType is true

But it doesn't justifies why KClasses having same string representation are different. At least it's confusing. And it's good idea to note about that in docs.

like image 866
Markus Marvell Avatar asked Mar 18 '16 22:03

Markus Marvell


1 Answers

In your case equality fails because KClasses are considered equal when they correspond to the same Java's type, not the same Kotlin type. This is false for int and java.lang.Integer.

The workaround is to use KClass's javaObjectType property, which will return Java class (not primitive type) even for Kotlin type compiled into Java's primitive:

 fun sameClass(c1: KClass<*>, c2: KClass<*>) = c1.javaObjectType == c2.javaObjectType

 sameClass(Int::class, (1 as Any?)!!.javaClass.kotlin) //true

I agree that this semantics is rather confusing, I filed an issue about it.

Also, KClass doesn't reflect nullability of Kotlin types, and in case if you need to work with declared Kotlin types precisely, you will need to use KType, which does.


UPD: the issue has been marked as fixed, and the equality is explained in KClass.equals KDoc since 1.0.2.

like image 91
hotkey Avatar answered Sep 21 '22 23:09

hotkey