Handling nulls
Avoid returning null is all you need to avoid handling them. Quoting NOOO:
Options over nulls
Before digging into the argument, let’s take something simpler.
One of the worst thing of imperative code is all that ugly null checks.
Anyway please don’t feel disappointed, before realizing and getting in touch with FP; I as first filled my code with these.
For example take a C# code snippet like this that returns a collection of Order
types.
var orders = DB.GetOrdersByDate(DateTime.Now);
if (orders != null)
{
foreach (var order in orders)
{
// do something with order
}
}
There’s no reason to design DB.GetOrdersByDate()
to returns a null
when no Order
satisfies the request. An empty collection, easly obtainable with
return Enumerable.Empty<Order>();
would be great, the following code could became
var orders = DB.GetOrdersByDate(DateTime.Now);
foreach (var order in orders)
{
// do something with order
}
When orders
value is empty (or better an empty collection) no iteration will be performed, hence no kind of check is required.
Anyway cases could present in which you must check for order presence (in the old semantic the null
check).
Now we can elegantly write:
var orders = DB.GetOrdersByDate(DateTime.Now);
if (!orders.Any())
{
// no orders
}
Because this code is semantically correct, hence is intrinsically more robust.
MayBe monad
As Mark Seemann says in this article: the BCL already has maybe monad.
He proposes the following construct through extension method:
public static class LightweightMaybe
{
public static IEnumerable<T> Maybe<T>(this T value)
{
return new[] { value };
}
}
So when you face an API (which you can change or not wrote by you) you can treat it like the sample above.
var client = LegacyDB.GetSingleClient(id: “101”);
if (client.Maybe().Any())
{
// result is not null
}
As you can see this extension method put the T value
inside a generic IEnumerable<T>
, in this way you can use the beatiful Linq syntax to write readable code that clearly states its intent.
But this mean you should design code that returns null
? No, you shouldn’t. I take the extreme position that returning a null
is comparable to having a bug in the code.
If you can refactor LegacyDB.GetSingleClient()
change its signature from:
public Client GetSingleClient(string id)
{
if (found)
return new Client(...);
return null;
}
to
public IEnumerable<Client> GetSingleClient(string id)
{
if (found)
return new Client[] { new Client(...) };
return Enumerable.Empty<Client>();
}
There’s nothing bad neither logically neither semantically to have a method handling one item returns a collection containing one item or otherwise an empty collection.
To me it’s wonderfully clean, clear and concise!
Alternative
However I can understand criticism to this design, that could distract you from the main argument of this post: not returning null
to avoid handling it.
You can design the method above using a singleton like string.Empty
following the Write once immutability pattern, as explained in this Eric Lippert article.
public Client GetSingleClient(string id)
{
if (found)
return new Client(...);
return Client.Empty;
}
The fundamental point here is that having a value, is always better than handling a null
.
This is the reason why functional language like F# use option monad to describe if a result has or has not a value.
When keep it
New compiler constructs and projects like Code Contracts could remove also this necessity.
But for now there’s nothing bad to check null
to validate method parameters.
public Client GetSingleClient(string id)
{
if (id == null)
throw new ArgumentNullException("id");
if (found)
return new Client(...);
return Client.Empty;
}
However also here my opinion is a bit extreme: guard clauses are just against null
; everything else falls into other application concerns such as validation.
But deepen it goes beyond the purpose of this post.
Conclusion
This blog post starts with a reference to NOOO. This is because this work is extracted from an unfinished and partly unpublished document.
The project aims to defined guidelines for developers who want to design API adhering to functional concepts from multi-paradigm languages like C#.
If you’re interested in this collaborative work, write to me (gsscoder AT gmail DOT com) or ping me via Twitter (@gsscoder).
Or visit this web site in status of work in progress.