The Problem

If you’ve coded for long enough in any mainstream OOP language, you’ve probably been bitten by the nastyNullReferebceException(or NullReferebceException)

The fact that null is the default value for all references has even been called The Billion Dollar Mistake by its own creator, due to the countless bugs it introduced, “which have probably caused a billion dollars of pain and damage in the last forty years” .

An example

The following code depicts a simple interface for a repository:

What’s potentially wrong with this code? As an experienced developer, you may guess that you’ll have to check for null when calling an implementation of this method. But that’s really up to you to remember (or find out the hard way).

A sample usage of the customer repository on a ASP.NET Web API controller method could be something like the following:

It’s a pretty common pattern:

  1. You retrieve something that may (or not) exist
  2. If that something does not exist: abort or return a default value (often null again, yikes).
  3. If that something exists: perform some computation(s) with it (here shown as mapping to a DTO).
  4. Return computed value.

Functional programming to the rescue

Functional programming has an elegant way to model these scenarios where a function may (or not) have something useful to return: it’s called Maybe (in Haskell) or Option(in F#) type.

Unfortunately, C# still doesn’t provide this type for our convenience (unlike Java, which has Optional).

However, there are already a few libraries that implement this very well. One of them is language-ext, which by no means is only around Option type. It presents itself as a a base class library for functional programming (for C#).

Essentially, an instance of an Option<T> can either be

  • None, meaning that the value is absent
  • Some<T>, you’ve guessed it, there’s a value of T.

Important note: Option<T> is a struct, so an instance of it can never be null.

Sample usage in C#

For any method that returns some instance T that might exist (or not) you can wrap the returning type with an Option<T>, as follows:

Looking at this code it’s pretty obvious that what comes out of that method might have (or not) a value. Plus, we’ll have to deal with that scenario, the compiler will not let us ignore that. So, in a way, it’s also a form of self-documenting code (the best kind of documentation).

Refactoring the above shown piece of controller code to use this new version could produce something like this:

Pretty neat, huh?

The Map method allows us to perform computations for the Some<T> case. For the None case, it simply skips over it. The result of a Map over an Option<T> is another Option<T>, so we can compose multiple Maps over it.

As for Match, it accepts two delegates, one for each of the possible cases. The first one (Ok) is for the Some<T> case and the second (NotFound) for the None case. In essence it’s a functional if (...) else (...)

Other Option available methods (besides Match and Map) include

  • IfNone(A noneValue), with which you can provide a default value if it’s the None case
  • IsSome and IsNone properties
  • you can check the comprehensive documentation here.

Conclusion

I really believe that being explicit about the nature of return types of methods in your code is hugely beneficial in the long run (both for bug prevention and for documentation).

However, this approach has also some drawbacks:

  • This may feel a bit alien for some developers (I think this could be mitigated if .NET BCL included this type)
  • We have to import some package (or roll our own, if we suffer from NIH syndrome), and make our consumers import it as well. This is why I’m more inclined to use this in the internal details implementation of our APIs (basically, in the domain layer).

If you like this approach, I encourage you to learn at least the basics of functional programming, (there’s so much more than this).

Written by André Carvalho • November 12th, 2018

Fonte: medium.com

Based in London and with offices across Manchester, Lisbon and Porto, YLD offers consulting services in software engineering, digital product design and training programs.