Kotlin: equal comparison seems OK on nullable, but greater than comparison is not
As you've found, Kotlin's equality operators (==
and !=
) can handle nulls, while the order comparison operators (<
, <=
, >
, >=
) can't.
This is probably because it's obvious what equality checks should mean for nulls — two nulls are clearly equal, and a non-null value should never equal a null — while it's not at all clear what it should mean for order comparisons. (If null isn't < 0, does that mean null >= 0? If not, you no longer have a well-defined ordering.)
This is reflected in the implementation: Any
has an equals()
method, indicating that all objects can be checked for equality. (Kotlin's documentation makes it explicit, as does that for the underlying Java method, that non-null objects must never equal null.) And Kotlin's implementation of the ==
and !=
operators explicitly checks for nulls. (a == b
translates to what you have to spell out in Java: a == null ? b == null : a.equals(b)
.)
But order comparison is handled differently. It uses the Comparable
interface: only types with a ‘natural ordering’ implement that; those that don't, can't be compared in that way. Since null can't implement any interfaces, it can't have a natural ordering, and the compiler prevents you trying the comparison. (Kotlin's documentation doesn't make this explicit, because the parameter is non-nullable; but that for the underlying Java interface says that such a comparison should return a NullPointerException.)
As to how you should handle this, the Elvis operator is probably the most concise solution:
if (mouseEvent?.clickCount ?: 0 >= 2)
If mouseEvent
is not null, this will get its clickCount
; otherwise, the safe-call ?.
will give the null directly, and then the ?:
will substitute 0. (That would also happen if the clickCount
held null, though that shouldn't be possible.) In every case, you end up with a non-nullable integer that can safely be compared with 2.
Of course, in practice, nothing should ever be calling a listener method and passing a null event. (I can't recall ever allowing for that back when I used to write Java Swing code for a living, or hitting any problems as a result.) So a simpler alternative might be declaring the parameter as non-nullable. But handling the null properly is just that little bit safer; and in this case, it doesn't add much extra code. So it's up to you!