Operator overloading generates NullPointerException

Kotlin doesn’t seem to protect against NullPointerException when using operator overloading:

import java.util.*

fun main(args: Array<String>) {
    val today = Date()
    val other: Date? = null
    if (today > other) { // This condition will throw a NullPointerException at runtime
        ...
    }
}

Some options:

  • Don’t allow comparing against nullable types
  • Allow this comparison but handle null in a way that is consistent with “==” and null is smaller than all other values (this would need to be documented)

I believe this is caused by Date being a Java type. Were it written in kotlin with a proper nonnullable operator fun, you would not face this issue.

Correct. The comparison expression is equivalent to today.compareTo(other) > 0, where Date#compareTo() is defined in Java and take a Date! as argument (which Kotlin assumes may be null). If you were to flip the expression, the compiler would complain that you are invoking compareTo on a nullable reciever. If you use a Kotlin class with a compareTo taking a non-null, you will also get a compile error.

I still think this could be considered a bug. One of Kotlin stated goals is to reduce NPEs. Yes, with the way that platform types work this behavior is expected, but I think one can argue that there can (and should) be an exception for operators.

  1. there is only one operator, which can be defined from within java. This alone warrants special treatment of the interop here. (Ok not true, == also can be, but equals handles null)
  2. the contract for Comparable states:

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

This means that the argument for compareTo basically has a NotNull annotation implied (although it is not stated in code.
I think it is fair to say, that calling compareTo with null is nearly never intended and if the caller wants an NPE there is always !!.

2 Likes

@Wasabi375 Good catch regarding the Comparable contract. Posted defect:
https://youtrack.jetbrains.com/issue/KT-25484

Thanks