Published by Marco on 8. Aug 2014 10:19:20
------------------------------------------------------------------------

I've seen a bunch of articles addressing this topic of late, so I've decided to
weigh in.

The reason we frown on returning null from a method that returns a list or
sequence is that we want to be able to freely use these sequences or lists with
in a functional manner.

It seems to me that the proponents of "no nulls" are generally those who have a
functional language at their disposal and the antagonists do not. In functional
languages, we almost always return sequences instead of lists or arrays.

In C# and other functional languages, we want to be able to do this:


var names = GetOpenItems()
  .Where(i => i.OverdueByTwoWeeks)
  .SelectMany(i => i.GetHistoricalAssignees()
    .Select(a => new { a.FirstName, a.LastName })
  );

foreach (var name in names)
{
  Console.WriteLine("{1}, {0}", name.FirstName, name.LastName);
}

If either GetHistoricalAssignees() or GetOpenItems() might return null, then
we'd have to write the code above as follows instead:


var openItems = GetOpenItems();
if (openItems != null)
{
  var names = openItems
  .Where(i => i.OverdueByTwoWeeks)
  .SelectMany(i => (i.GetHistoricalAssignees() ?? Enumerable.Empty())
    .Select(a => new { a.FirstName, a.LastName })
  );

  foreach (var name in names)
  {
    Console.WriteLine("{1}, {0}", name.FirstName, name.LastName);
  }
}

This seems like exactly the kind of code we'd like to avoid writing, if
possible. It's also the kind of code that calling clients are unlikely to write,
which will lead to crashes with NullReferenceExceptions. As we'll see below,
there are people that seem to think that's perfectly OK. I am not one of those
people, but I digress.

The post, "Is it Really Better to 'Return an Empty List Instead of null'? / Part
1" by Christian Neumanns

serves as a good example of an article that seems to be providing information
but is just trying to distract people into accepting it as a source of genuine
information. He introduces his topic with the following vagueness.

"If we read through related questions in Stackoverflow and other forums, we can
see that not all people agree. There are many different, sometimes truly
opposite opinions. For example, the top rated answer in the Stackoverflow
question Should functions return null or an empty object? (related to objects in
general, not specifically to lists) tells us exactly the opposite:

"Returning null is usually the best idea ..."

The statement "we can see that not all people agree" is a tautology. I would
split the people into groups of those whose opinions we should care about and
everyone else. The statement "There are many different, sometimes truly opposite
opinions" is also tautological, given the nature of the matter under discussion
-- namely, a question that can only be answered as "yes" or "no". Such questions
generally result in two camps with diametrically opposed opinions.

As the extremely long-winded pair of articles writes: sometimes you can't be
sure of what an external API will return. That's correct. You have to protect
against those with ugly, defensive code. But don't use that as an excuse to
produce even more methods that may return null. Otherwise, you're just part of
the problem.

The second article "Is it Really Better to 'Return an Empty List Instead of
null'? - Part 2" by Christian Neumanns

includes many more examples.

I just don't know what to say about people that write things like "Bugs that
cause NullPointerExceptions are usually easy to debug because the cause and
effect are short-distanced in space (i.e. location in source code) and time."
While this is kind of true, it's also even more true that you can't tell the
difference between such an exception being caused by a savvy programmer who's
using it to his advantage and a non-savvy programmer whose code is buggy as
hell.

He has a ton of examples that try to distinguish between a method that returns
an empty sequence being different from a method that cannot properly answer a
question. This is a concern and a very real distinction to make, but the answer
is not to return null to indicate nonsensical input. The answer is to throw an
exception.

The method providing the sequence should not be making decisions about whether
an empty sequence is acceptable for the caller. For sequences that cannot
logically be empty, the method should throw an exception instead of returning
null to indicate "something went wrong".

A caller may impart semantic meaning to an empty result and also throw an
exception (as in his example with a cycling team that has no members). If the
display of such a sequence on a web page is incorrect, then that is the fault of
the caller, not of the provider of the sequence.

  * If data is not yet available, but should be, throw an exception
  * If data is not available but the provider isn't qualified to decide, return
    an empty sequence
  * If the caller receives an empty sequence and knows that it should not be
    empty, then it is responsible for indicating an error.

That there exists calling code that makes assumptions about return values that
are incorrect is no reason to start returning values that will make calling code
crash with a NullPointerException.

All of his examples are similar: he tries to make the pure-data call to retrieve
a sequence of elements simultaneously validate some business logic. That's not a
good idea. If this is really necessary, then the validity check should go in
another method.

The example he cites for getting the amount from a list of PriceComponents is
exactly why most aggregation functions in .NET throw an exception when the input
sequence is empty. But that's a much better way of handling it -- with a precise
exception -- than by returning null to try to force an exception somewhere in
the calling code.

But the upshot for me is: I am not going to write code that, when I call it,
forces me to litter other code with null-checks. That's just ridiculous.