If nulls are lemons, it’s high time someone made some damn lemonade…

Let’s dive right in — I’m going to tell you why I don’t mind the null reference, and why I think it can be a useful tool and functions well as a default value for reference types on models. My end-goal here is to expose convenient patterns and language features to you that null references help make possible.

That’s an expensive lemon!

At this point, we’re all familiar with Tony Hoare’s opinion on his introduction of the null reference into modern computing way back in 1965. He’s often quoted on his “billion-dollar mistake” and, for a while, that was all I needed to dislike the null reference. Null references put the responsibility of preventing crashes, when invoking on reference types, directly on the shoulders of the programmer, and the programmer can be a lazy, lazy beast. I primarily develop for Android these days, so the bulk of my development has been in Java, specifically Java 7, and wow can it tedious. How many times have you dealt with a case like this? —

Looks concise, but if aFoo.bar is null, it’ll throw a NullPointerException . We worship at the Altar of Bloch, so we obey Commandment 38: Thou shalt validate parameters. So, our code ends up looking like this —

We’ve added a bit of boilerplate, but the code is much safer. I’m not trying to belabor the point, honestly, but I just want to make it clear that using nulls in Java can be a tedious practice. Now, you could handle this check at various points in your application, as long as it’s before access, but you must always do it.

What about default values?

Some developers are advocates of tossing some default values onto references in order to avoid the dreaded NPE. It seems like a great solution at first, but let’s examine what I consider to be some of the pitfalls:

Default values require knowledge of consumed API implementation details. Consider the case that your default values are rejected by APIs you’re consuming. At that point, you need to invest extra time into satisfying the API’s underlying implementation, and that’s not a great solution either, is it? Here’s an example —

This will generate an exception just as fast as any null reference, and what’s more, it’s now specific to the implementation of the API. You could provide a default date string that’s formatted to the API’s taste, but then your model becomes tied to that API’s implementation. Sure, we could check for the empty string value ahead of time, just like we did the null, but have we gained anything by doing so? Seems like it’s just an abstracted null check. What about a different default value on a different type? That brings me to another point.

2. Defaults values will differ across types, and across implementations. Consider the following implementation of three different models —

Do you see how we now need to know what each model considers to be its default state values across each implementation? Unless there’s a master record of default values, it’s a model implementation detail. Even if there were a master record, you would need to perform the same checks for default values in order to take alternative steps, or risk leaking the values into inappropriate layers. We’ve introduced edge cases that may require extra domain knowledge, eliminated no code, and things are arguably more tedious to handle.

3. Defaults can cause silent failure that leaks into the UI. It can create a confusing user experience when you fail to detect and handle default values properly. This most often occurs in the case of default String instances, as that’s what we commonly bind to the UI elements. Binding default values like “DATA NOT PRESENT” lets the user know you were not expecting or checking for errors, and that you’re fine with letting them know that something has happened you’ve not accounted for. A more widely-accepted solution is to implement an error state and show it to them. That requires checks, and reiterates the previous points.

4. Defaults hide the real issue: values have failed to be initialized. Some would argue that we’ve gained the ability to invoke methods on a default type instance without crashing due to unhandled NPEs. Let’s consider this for a moment: what we’ve actually gained is the ability to hide the real problem from ourselves. The value is uninitialized and some other steps need to be taken — nothing is gained by manipulating a default instance that was expected to be a real value.

The devil you know

Okay, so let’s talk about sticking with the null reference for all defaults. What do we gain? How is it better? What about Tony Hoare’s quote? Well, here we go —

It’s applicable to all reference types, so we can check for it easily without the need of specific domain knowledge. We can abort the operation, log it, specify other execution paths, etc. Why am I advocating this? It’s still tedious as hell, right? Well, when we only have one value that signifies a reference is unassigned, we can easily build constructs to gracefully handle cases of its occurrence. Null references are referred to as the billion dollar mistake because developers can be lazy and irresponsible. It’s akin to giving you enough rope to hang yourself. In the right hands, however, rope is a useful tool.

Enter the Optional

https://github.com/carterhudson/RxOptional (shameless plug)

We programmers hate repeating ourselves so, naturally, we’ve managed to come up with ways to have these null checks performed implicitly. The most widely-applied version would probably be the Optional construct. Now, if you’re in Android land, this construct may not be something you’re terribly familiar with since you don’t get it for free. That said, it’s a construct that has numerous specifications for implementation, and there are many, many libraries that will happily give you access to one. If you are familiar, bear with me, and if you’re not — let me explain. In a nutshell, it’s a wrapper around a value that may or may not be null. In more robust implementations of the Optional concept, one can dictate control flow in a fluent fashion via the Optional API. Methods like ifNull(...) and ifNotNull(...) let you pass an instance of a functional interface, a functor, as an execution block. Here’s a quick example without getting into the implementation details —

Wow, that feels pretty good, doesn’t it? I’ll admit, the lambdas help, but ideally you’d never have to manually write null-checks for accessors again. Personally, I’m a big fan of functional programming, so I tend to implement it with methods like mapIfNotNull(...) and flatMapIfNotNull(...) , but that’s beside the point. The point is: we can work well with null references in Java. But is there a better way? Hell yes there is — use Kotlin.

Tastes like lemonade

So let’s talk about null references in Kotlin. Kotlin’s type safety system is aimed at eliminating the danger of the null reference. Don’t take it from me; here’s a direct quote from their page on null safety:

Kotlin’s type system is aimed at eliminating the danger of null references from code…

Told you so! To do this, Kotlin enforces a couple things right off the bat.

You can’t assign null to anything unless you’ve explicitly specified that you want it to be nullable. For example, String becomes String? . Simple! If you’ve specified that you’re expecting nulls, the language forces you to unwrap the value for use, just like the Optionals discussed above. If you don’t, it’s a compile-time error

Choose your own adventure

Can we use it gracefully to dictate control flow like the Optional example? Sure can. —

What’s in that let construct will only execute if aString is non-null. The use of it refers to the smart-casted instance of non-null aString , but that’s a bit beyond the scope of this article, and there are plenty of resources online that go into greater detail. For now, let’s ask another question: what about in the case that aString is null? It’s all well and good to have a non-null happy-path, but that doesn’t solve the problem of control-flow switching, does it? Wouldn’t it just silently fail and do nothing? Have no fear, the ?: (referred to as Elvis) operator is exactly what you’re looking for! It looks the way it does because it’s something of a condensed case of ternary-if usage. Ever written something like the following?

a = (a != null) ? a : b

The Elvis operator is something like that, but less redundant. The previous code becomes something like

a = a?: b

Nifty! Let’s compose it with our previous non-null execution block —

Now, in the case that aString is null, doSomethingElse() is invoked. It can be used to log errors, initialize the null value, or really just about anything else. We’ve replaced ugly, manual null-checks with an elegant, concise block that is directly supported by the language, and we can specify default values for binding without tying them to the context of our models! Surprisingly easy, and powerful. This is why I prefer to make liberal use of nullable types, and why I think null references can serve well as default values.

With all that said, there actually are a couple ways to circumvent Kotlin’s compile-time checks and give yourself an NPE — but you have to be very explicit about it.

Kotlin has the keyword lateinit that basically lets you treat a reference type like a Java field. You can set it to null, and nothing will stop you from invoking methods and causing NPEs. I try to avoid using lateinit , but sometimes it’s necessary for DI frameworks that initialize values in lifecycle hooks outside the init block of a class. The explicit unwrap operator !! is your way of asserting that the value you’re retrieving is non-null, and that Kotlin should go pound sand instead of telling you how to handle your business. If I can help it, I tend not to use this. That said, it’s not a perfect world and, at some point, you may find yourself needing this. If you do invoke this operator, be cognizant that Kotlin is no longer holding your hand!

Caveats

Like everything in life, this also has a downside. Your data types that have primitive counterparts, having been assigned null, will be evaluated as reference types and forego conversion to their primitive versions. A Kotlin Int assigned null will be the equivalent of a Java Integer reference type instead of an int , and so on. In heavy computing situations, this could cause some performance issues, but by and large it’s a non-issue. Just something to be aware of.

Conclusion

Phew! I’m glad you stuck with me through that. We made it past the quote and found a nice application for null references. There’s always going to be some onus on the programmer to take proper precautions, but we can make life a bit easier in the meantime. I hope this was helpful in explaining why I think the null reference is a decent default value. Feel free to comment or leave feedback. Happy coding, friends!