Why Optional is better than Null

Aug 31, 2016•
6 min read

languagesobject-thinkingmonadfunctional-programming

null returning and checking is everywhere and it developed deep roots in the imperative programming world.
It’s more than time to stop using it and to look into better ways to deal with fallible computation.

Some attempts were made to work around this such as the Null Object Pattern which I don’t really like because it’s a solution to be applied to every class that might be used as return type where null might be returned instead.

What’s the problem with using Null?

I see a few to start with:

Null is not an object

It makes code implicit and therefore not trustable

It requires defensive programming (null checking), making it dirty

Let’s consider the following method declaration:

publicfinalCategoryfindCategoryById(longcategoryId);

This method declares that it returns a Category object, having its category id.
But, is it really? I mean, can I trust this code and relax?

What if I implement that method like this?

publicfinalCategoryfindCategoryById(longcategoryId){returnnull;}

In such case I’m not - at all - returning a Category, so the code is not saying the truth. And that is bad.

We need to consider that it might happen that no such category exists with the given id.

Optional to the rescue

Optional is here to help us and we shouldn’t just keep it aside.
Optional is a wrapper around a value of type T that might actually be nothing. This not only encapsulates the null checking in a single place but also makes us design and reason rigorously about our code.

For example, in Haskell there is no such thing as a null but the Maybe a type:

dataMaybea=Justa|Nothing

I don’t think of Optional as any modern solution to replace the usage of null verifications but as a design solution that should have been there from the beginning.

Now imagine the impact that such different design and approach will have in your system as a whole…

What if we can’t change the method declaration?

Let’s suppose you are using some web service or some database API that doesn’t yet use Optional and / or throws exceptions and you don’t want either to check nulls all around the code either deal with the exceptions.

The solution is to wrap it up!
Create wrapper classes that will bridge the outside data source nulls or exceptions into your internal convention ( [null|Exception] -> Optional).

Suppose that the method above is such case.
I could wrap that (service) method like this:

classMyService{privatefinalOutsideServiceservice;(...)//Example #0 - if it returns nullpublicfinalOptional<Category>findCategoryById(longcategoryId){returnOptional.ofNullable(service.findCategoryById(categoryId));}//Example #1 - if it throws an exceptionpublicfinalOptional<Category>findCategoryById(longcategoryId){try{returnOptional.ofNullable(service.findCategoryById(categoryId));}catch(Exception_){returnOptional.empty();}}}

Some final considerations

If you find it too much effort to opt for this wrapping logic either because the wrapped services have too many methods or you just find it too much to code, I understand your point.
I can’t choose for you but we may agree that it looks better to ensure code correctness than to resign to the way it’s done elsewhere and do the same internally.

If you just don’t like the idea of repeating all those try-catch blocks, I get you there, but it’s something easy to abstract (and I will soon post something about it).

Is Optional enough for every situation?

No. Optional represents results of computation that might or not have failed but when you are left alone with an Optional.empty() you don’t really have much information about the context of the failure.
In some cases, it is not even necessary to have such context but in other cases it is and there are ways to approach that.

In Haskell, for such cases there is the Either type, defined as follows: