I am a software engineer at Google on the Android project and the creator of the Java testing framework TestNG. When I'm not updating this weblog with various software-related posts or speaking at conferences, I am busy snowboarding, playing squash, tennis, golf or volleyball or scuba diving. Cedric is a DZone MVB and is not an employee of DZone and has posted 90 posts at DZone. You can read more from them at their website. View Full User Profile

A Note On Null Pointers

08.22.2012
| 4684 views |
  • submit to reddit

It’s the second time in a few weeks that I have read something along the lines of:

In a year at foursquare, I’ve seen exactly one null pointer exception.

To me, this kind of statement is similar to

Ever since I switched to BASIC, I haven’t seen a single stack trace.

and it shows a fundamental misunderstanding of what a programming error is. Similarly, hearing Tony Hoare say that introducing null was a “one billion dollar mistake” makes me really question if he understands the fundamental idea behind crashes.

Null pointer exceptions, stack traces, core dumps, guru meditations, etc… are usually all the manifestation of a simple phenomenon: unexpected values. Somehow, your code expected a value but received another one. This is a programming error, also known as a bug.

If you are using a language that supports monadic Option/Maybe types, by definition, you will not be seeing any null pointer exceptions, but this doesn’t mean that you have solved the “unexpected value” problem.

In languages such as Java or C, null pointers translate into crashes that are hard to miss and usually easy to diagnose. What would be the equivalent of this in Scala?

The answer is easy: receiving a None when you expected a Some. Because of the way you thread monads through your functions, such a bug will not trigger any exceptions nor any crash: your None value will happily make its way through monadic transforms and will simply result in a no-op every time it’s being mapped. Of course, your program will yield an unexpected value that you will take notice of at some point, and then you will have to go through the painful process of retracing all the Options that your transformations have gone through to find out which one returned None when it should have returned a Some.

At this point, you should probably ask yourself: if this piece of code should never return a None, why return an Option at all? In such cases, you are better off unboxing your Option and returning its raw value. Of course, the downside of this is that you might have to lift your value again if the following computations happen in the Option monad as well.

As you can see, Options come with their own trade offs and hard design decisions as well. No such thing as a free lunch.

Which leads us to the next big misconception about this class: Option doesn’t solve null pointer exceptions nor unexpected values, it just saves you from having to test against null. And actually, doing so (e.g. pattern matching your option against Some/None) is usually considered bad practice, even though it’s sometimes necessary for Java interoperability reasons.

Personally, I favor the way Groovy, Fantom and Kotlin address the problem over having to lift all my values into Option. For example, here is how Kotlin lets you ignore null values encountered along a chain of invocations:

bob?.department?.head?.name

If either of these accesses returns null, the result of this expression will be null. No need to put your values into monadic boxes nor mapping through them, just use the standard composition operator you are familiar with if you are using a C family language.

By all means, do use Option whenever you can if you are programming in Scala (and you will probably realize that you can’t use it as much as you would like because Java libraries, and some Scala ones, are just not implemented to take Option parameters), but don’t listen to people who tell you that because you are no longer seeing any null pointer exceptions, your code is safer. It’s not. You still have to fix your bugs.

Published at DZone with permission of Cedric Beust, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Tomasz Nurkiewicz replied on Thu, 2012/08/23 - 8:15am

NPE happens when you want to access nullable reference without null-checking first. In Scala idiomatic way to represent nullable value is to use Option. The big difference is that I can't access Option without checking first (raw get() is just wrong in most cases), using pattern matching, isDefined or preferably monadic constructs. This means I am forced to handle situations where NPE would normally happen.

I found myself writing much safer code in Scala because if I get Option, I must take both cases (Some and None) into account. I cannot just ignore that fact. On the other hand if I have a reference, it must be non-null. When I get a reference from Java code/library that can be null, I just wrap it: Option(javaReference).

But what I love the most about Option[T] is that it clearly documents the type. In Java/Groovy/... a reference can, or can't be null, you never know. You either defensively check or let NPE happen. In languages with Option/Maybe the expected value is clear from the very beginning.

And for completeness the safe navigation operator in Groovy translated to Option[] and map:

bob.map(_.department).map(_.head).(_.name).orNull

Rajesh Pitty replied on Fri, 2012/08/24 - 1:34am

null can/may be an unexpected value, but not all unexpected values are null.

why do you even need a null pointer?

why do you even pass a null when you can pass a default value ? wont that avoid the NPEs?

 

as you said null pointers translate into crashes. if i dont have null pointers my code wont crash.

 null is annoying.

 

 

 

Robert Elliot replied on Fri, 2012/08/24 - 2:23pm

The point of Option, as with all strong typing, is that it documents the nature of a value and enforces it via the compiler in a form no programmer can miss. That's why it removes the equivalent of NullPointerExceptions - it forces the caller of a method that might return no value to recognise that fact and hence vastly improves the probability that they handle that case appropriately. Where null is routinely used to mean no value programmers regularly forget to check for it or check for it needlessly, polluting the code base in the process. 

Lund Wolfe replied on Sat, 2012/08/25 - 10:46pm

An NPE is usually a design flaw, often an unanticipated use case.  It's usually easy to find and catch but it usually wasn't caught early enough and trickled down and the root cause needs to be fixed, or repaired in the data, where it is identified in the code, if caused by existing inconsistent or incomplete data.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.