I have a following code snippet in Kotlin:
val pair: Pair<Char,Char> = 'z' to 'z'
val comparison = pair.first.compareTo(pair.second)
println(comparison)
It fails at the second line with the following exception when I try to run it:
java.lang.ClassCastException: java.lang.Character cannot be cast to java.lang.Number
IDE (IntelliJ) doesn't complain about any wrong type. The issue is somehow related to the fact that Chars are coming from Pair<Char, Char>
because 'z'.compareTo('z')
works fine. Do you know how Kotlin resolves the following call?
I'm using Kotlin 1.0.4
TL;DR Apparently, this is a compiler bug.
The reason for this behavior lies in the bytecode that the Kotlin compiler generates for these two calls. (If you use IntelliJ IDEA, you can inspect the bytecode using the bytecode viewing tool).
First, the bytecode generated for the 'z'.compareTo('z')
call is:
LINENUMBER 10 L3
BIPUSH 122
BIPUSH 122
INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I
It calls kotlin.jvm.internal.Intrisics.compare()
that compares two Int
s, and the Char
s are pushed to the stack directly as Int
s (BIPUSH
means push byte as integer).
But if you look at the bytecode for pair.first.compareTo(pair.second)
, you will find something like this:
ALOAD 1
INVOKEVIRTUAL kotlin/Pair.getFirst ()Ljava/lang/Object;
CHECKCAST java/lang/Number
INVOKEVIRTUAL java/lang/Number.intValue ()I
ALOAD 1
INVOKEVIRTUAL kotlin/Pair.getSecond ()Ljava/lang/Object;
CHECKCAST java/lang/Number
INVOKEVIRTUAL java/lang/Number.intValue ()I
INVOKESTATIC kotlin/jvm/internal/Intrinsics.compare (II)I
It calls kotlin.jvm.internal.Intrisics.compare
, too, but here's what it tries to do before:
ALOAD 1
and INVOKEVIRTUAL ...
lines) Number
(CHECKCAST ...
)java.lang.Number.intValue()
(INVOKEVIRTUAL ...
)The second and the third lines are the culprit, Char
is not a Number
. It simply looks like the compiler generated incorrect bytecode for this comparison (it would be correct for the Number
types, seems like Char
is just not handled separately).
There is an issue about this in the Kotlin issue tracker, it will likely be fixed in future releases.
To fix the call in your code for now, you can convert the Char
s manually before the call:
pair.first.toInt().compareTo(pair.second.toInt())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With