Right. Both Java and Kotlin’s approaches have merit. But I’ll argue, in this case, Kotlin is the greater of two evils.
Sure. Java’s “always nullable” approach forces null checks, which sucks. On the other hand, a null check is universal and is easy to manage. Of course the runtime danger is an NPE, but these tend to be relatively easy to diagnose and fix and rarely involve data corruption (the worst of dangers).
Kotlin’s “non-null by default” approach prevents null checks, which is nice. But consider the example in the original post. The author of the class assigns an empty string to initialize the variable, otherwise the compiler complains because it can’t be null. Essentially, the programmer hasn’t thought much about whether or not the value should be nullable, he has simply substituted an empty value for null because THE COMPILER TOLD HIM TO. Can you see how this is a dangerously common behavior precipitated by the language’s choice to avoid null values?
User’s of the variable are under a false sense of security. The variable can’t possibly be null, the compiler made sure of that, but now we have a much worse problem:
We no longer have a universal way to check (or assign) uninitialized state.
Above all, we likely won’t check for “emptiness” because the whole idea behind non-nullable is to avoid null checking and NPEs. Therefore, we let potentially uninitialized state slip through and increase the risk for data corruption since code downstream will not throw NPEs, which otherwise signal to us we are working with bad data.
Don’t misunderstand. I fully respect the benefit of non-nullable state, but it comes with great responsibility that I argue is not fully respected or easily understood. Alas, the danger is that many consider non-nullable a magic bullet. “Yay, we don’t have to check for null now because the compiler made it so.” Yeeaah, no. You could argue programmers will think critically and decide whether or not to override the default non-nullable behavior, but the language encourages the use of empty values with ERROR: property must be initialized. Again the example in this post speaks volumes.