Null is your friend, not a mistake

I’ve been programming in Java for a long, long time. I’ve learned what it takes to write and maintain big (as in million-lines of code) software in Java and I’ve witnessed industry-wide struggle to avoid and contain the dreaded (NPE) that seemed to plague any reasonably-sized Java codebase. This realization of the danger of the reference had dawned on the industry way before its inventor, Tony Hoare, had admitted in 2009 that null reference was his “Billion Dollar Mistake”.

It was not that obvious back in 1996 when Java 1.0 was released. Let us take a look at just one, now famous, example of a typical Java API from that era: method. It can be used to list contents of a directory like this:

It works only if the directory exists. Otherwise it throws an NPE, because returns . But who would ever write code like that? Not only documentation clearly states that it returns when directory is missing, but modern IDEs flag this particular code with a warning right away.

However, people do these kind of mistakes all the time when programming in Java. By now there is a big body of research showing how it happens. It turns out that most of the time our API functions are not supposed and are not expected by other developers to return null. In corner cases, like the absence of something, it is a convention in Java to return some “null object” (empty collection, unfilled domain object, etc) or, as a lesser evil than returning null, to throw an exception. That is how — a modern version of , is designed — no nulls anywhere.

So when null does appear as a result of a function in some special case, as performance optimization, uninitialized reference field, etc, it often catches other code off-guard, unprepared to deal with it. Not only it is rare to be having to deal with nulls, but the code you have to write for dealing with nulls in Java is long and verbose:

No wonder you’d rather choose not to write it, unless absolutely necessarily (necessity often happens when your customer discovers NPE in production).

Fear of null leads to some extreme practices. There are Java coding styles that forbid null completely, forcing heinous workarounds upon developers. Have you seen a codebase where every domain object implements a special interface and must provide manually coded “null object” instance? Lucky if you have not, but I bet you’ve seen wrappers that pollute Java code only for the sake of avoiding nulls.

There are collection-like APIs that forbid null elements out of extra caution and there are members of core Java team that consider support for nulls in Java collection framework to be a mistake. This is extremely sad.

The truth is that the concept of null is not mistake, but Java’s type-system, that considers null to be a member of every type, is. See, is a valid in Java and is a valid , too, yet you can use all the string methods like on the former, but attempts to use them on the latter universally fail at runtime. Is it type-safe? Not really. It is normal when some operations fail at runtime on certain values of a type (like division by zero), but when a value leads to runtime failure of all operations, it shows that the value should not belong to this type in the first place. All those NPEs in Java programs indicate an obvious flaw in Java type-system.

More type-safe programming languages, like Kotlin, fix this flaw by properly incorporating the concept of null into the type system. Adding inspections and warning does help, too, but it is not enough. Clearly, a sound type system must only allow such values of type that can support its operations, so in Kotlin putting into a variable of type is not just a warning, but a type error akin to assigning an integer value to a variable of type .

Proper null support in type system is a game-changer for API design. There is no reason whatsoever to fear null anymore. Having some functions that return a nullable type side-by-side with others that return non-null is as normal as having some functions that return side-by-side with others that return . They are simply different types with different and safe sets of operations available for them.

Type-safe null is better, more efficient, and less verbose alternative to represent all sorts of “missing results”. Look at Kotlin standard library for inspiration, for example. There is function that parses a string to an integer, if possible, or returns null if not. It is joy to use. Writing a command-line application that takes an integer parameter and properly complains on its absence is easy:

Embrace null in your API design. Null is your friend with Kotlin. There is no reason to fear it and no reason to work around it with “null object” pattern or wrappers, let alone with exceptions. Proper use of nulls in your APIs results in more readable and safer code, free from boilerplate.

Further reading

If you liked the topic and want to know more details from the standpoint of language design then consider reading the companion to this story— “Dealing with absence of value”.

Written by

Project Lead for the Kotlin Programming Language @JetBrains

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store