https://kotlinlang.org logo
Title
h

Hannes Korte

05/09/2023, 11:32 AM
Hi, today we spent some time finding a bug with an NPE on a non-nullable type. We simplified the scenario down to a small toy example to showcase the problem: https://play.kotlinlang.org/#eyJ2ZXJzaW9uIjoiMS44LjIxIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncy[…]xufVxuXG5mdW4gbWFpbigpIHtcbiAgICBwcmludGxuKEZvbygpKVxufSJ9
// This code compiles, but leads to an NPE on a non-nullable type
class Foo {
    val output = doSomething()
    val input = "This value is not set yet"
    fun doSomething(): String = input.uppercase()
}
The order of the class properties matters, as
input
is still
null
, when
doSomething()
is called. This is trivial to see in this example, but tricky in more complex scenarios. Is this expected behavior? Couldn't the compiler notice the nullability issue?
d

dmitriy.novozhilov

05/09/2023, 11:52 AM
It is a known problem (KTIJ-9751) Generally there is no solution for it in the compiler, which will work for definite amount of time, because it requires cross-functional analysis (which may lead to situation that you need to look through all the sources to understand that some call in the constructor is safe). There are some heuristics in the IDE plugin, but they don't cover all possible cases
There is a simple rule which helps to avoid such bugs: never leak
this
in class initialization (contstuctors, property initializers, init blocks), even to members of the same class
s

sciack

05/09/2023, 12:34 PM
Happen to me extending some Swing Component in Intellij plugin, the "Abstract" constructor was calling properties that was not initialised yet, I had to make the properties nullable even if was logically never null.
h

Hannes Korte

05/09/2023, 12:45 PM
Interesting, and thanks for the issue link. Also the rule to "never leak
this
in class initialization" is good to know.
p

peekandpoke

05/10/2023, 8:38 AM
Another workaround might be to make those properties lazy that depend on the class being initialized:
val output by lazy { doSomething() }