Why Scala’s “Option” and Haskell’s “Maybe” Types Won’t Save You From Null
The more I think about it, the less I understand the point in Scala’s Option class (which originated in Haskell under the name Maybe).
If you read the voluminous material that describes the concepts behind the Option class, there are two main benefits:
- It saves you from NullPointerException
- It allows you to tell whether null means “no object” or “an object whose value is null”
I claim that Option solves none of these problems. Here is why.
Here is a typical blog post showing the wonders of Option (I’m not singling out this particular person, you will find many posts making similar claims).
The examples in this post show that with the Option class, you can now have hash tables that contain null values and never be confused when a get() returns null. Fine, but in practice, I find that hash tables allowing null values are rare to the point where this limitation has never bothered me in fifteen years of Java.
The claim that Option eliminates NullPointerException is more outrageous and completely bogus. Here is how you avoid a null pointer exception with the Option class (from the blog):
val result = map.get( "Hello" )
result match {
case None => print "No key with that name!"
case Some(x) => print "Found value" + x
}
See what’s going on here? You avoid a NullPointerException by… testing against null, except that it's called None. What have we gained, exactly?
The worst part about this example is that it forces me to deal with the null case right here. Sometimes, that's what I want to do but what if such an error is a programming error (e.g. an assertion error) that should simply never happen? In this case, I just want to assume that I will never receive null and I don't want to waste time testing for this case: my application should simply blow up if I get a null at this point.
And you know what construct does exactly this? NullPointerException! Try to reference a null pointer and that exception will be thrown. It will make its way up the stack frames since you probably never catch it anywhere (nor should you) and it will show you a clear stack trace telling you exactly what happened and where.
In other words, it seems to me that the Option class is bringing us back into the stone age of using return values to signal errors. I can't imagine this being a progress (and I'm equally irritated at the Go language for making the same mistake).
When it comes to alleviating the problems caused by null pointer exceptions, the only approach I've seen recently that demonstrates a technical improvement is Fantom (Groovy also supports a similar approach), which attacks the problem from two different angles, static and runtime:
- Static: In Fantom, the fact that a variable can be null or not is captured by a question mark appended to its type:
Str // never stores null
This allows the compiler to reason about the nullability of your code.
Str? // might store null - Runtime: The second aspect is solved by Fantom's "safe invoke" operator, ?.. This operator allows you to dereference a null pointer without receiving a null pointer exception:
// hard way
Str? email := null
if (userList != null)
{
user := userList.findUser("bob")
if (user != null) email = user.email
}
// easy way
email := userList?.findUser("bob")?.email
Note how this second example is semantically equivalent to the first one but with a lot of needless boiler plate removed.
So, can someone explain to me how Option addresses the null pointer problem better than Fantom's approach?
- Login or register to post comments
- 4994 reads
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)




Comments
Sean Parsons replied on Fri, 2010/07/30 - 3:48am
Lukasz Zwierko replied on Fri, 2010/07/30 - 4:10am
I think you're missing a point here, I'm not much into scala but looking at the example from the post you've given link to (http://blog.danielwellman.com/2008/03/using-scalas-op.html) I see what authors really meant.
See the difference between Some(null) and None?
Some(null) == object is defined and references null
None == object is not defined/ uninitialized
I think that's the whole point. It doesn't savne you fron checking null pointeers, but it does enable you to distinguish between unnintialized value and valu initialized with null (if you'r into thiskind of programming).
Héctor Hugo Bar... replied on Fri, 2010/07/30 - 6:39am
I think main point of blog article is in last paragraph.
Scala's Option change runtime exception such as NullPointerException with a compile-time error, so developer cannot forget to handle the case (even if you want to).
Ricky Clarkson replied on Fri, 2010/07/30 - 6:45am
We have gained because we have done this deliberately. The insidious problem of null is that it is generally impossible to know whether a reference can be null, whereas we always know an Option can be None. x.foo() doesn't look any different whether or not it can throw a NullPointerException.
"The worst part about this example is that it forces me to deal with the null case right here. Sometimes, that's what I want to do but what if such an error is a programming error (e.g. an assertion error) that should simply never happen?"
There's nothing to stop you from throwing an exception at this point. Option has .get, which gives you the value or throws an exception. Again, the distinction is that dereferencing an Option looks different to dereferencing a nullable variable.
I'm pretty sure we've discussed this in the past; I'm surprised you still don't understand this, Cedric.
Josh Berry replied on Fri, 2010/07/30 - 10:18am
I believe you missed out on probably one of the nicer figures of options, the use of map/flatMap. Combined with for comprehensions, you can push many null pointer checks into a single spot.
Consider:
David Parks replied on Sat, 2010/07/31 - 4:05pm
I'd agree with Josh Berry and take it a step further -- the shining benefit is when used with monadic computation. Josh's examples are of that sort. As are your Fantom examples (when you note that Str? is basically a less verbose way of writing Option[String]). Either is another great example from Scala -- it largely replaces the explicit boilerplate required for exception handling.
I'd read just about everything you were talking about and I didn't get the point when I did, either. Its probably the case that it clicks differently for everyone but I can tell you that the moment I "got it" was when I read the first few pages of the Haskell All About Monads Tutorial. Now, I don't know Haskell... but the core points of the language are pretty simple and anyone who knows Scala can easily comprehend the first bit of this tutorial. It really communicates why you would care about monads, and when and how you write and use them.
Eric Giese replied on Mon, 2010/08/02 - 7:30am
1. If you use Option for all optional values, the callers do not need to check for null anywhere. Null-Checks then become a hint on bad design, as do instanceof-checks in JDK 1.5+ code. Also, if a NoPE appears anywhere, its easy to blame (and fix) the provider of the value, instead of discussing wether the caller must check for null.
2. Optional values require additional work on the callers side, but thats intentional:
In this case, the implementor now needs to reason wether this scenario is recoverable (-> use option) or a dead end (-> throw an IllegalStateException or something like this).
Also, unboxing isn't that much of an effort, if you are not interested for the "none" value:
for ( v <- value){
v.something();
}
Thats not much more work than a null check.
Ben James replied on Tue, 2011/04/05 - 11:08am
You've chosen a poor example. Matching on an Option is silly, because there are methods that can deal with the None case for you.
Here's how a Scala equivalent of your Fantom example might look:
val email: Option[String] = users.flatMap(_.get("ben")).map(_.email)Or, in for-comprehension syntax:
val email: Option[String] = for (userList <- users; user <- userList.get("ben")) yield user.emailJames Kear replied on Tue, 2011/09/06 - 3:33pm