Why Scala’s “Option” and Haskell’s “Maybe” Types Won’t Save You From Null
Join the DZone community and get the full member experience.
Join For FreeThe 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?
Opinions expressed by DZone contributors are their own.
Comments