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!