Null references aren't "shunned" any more so than exceptions, at least by anyone I've ever known or read. I think you're misunderstanding the conventional wisdom.
What's bad is an attempt to access a null reference (or dereference a null pointer, etc.). This is bad because it always indicates a bug; you would never do something like this on purpose, and if you are doing it on purpose, then that's even worse, because it's making it impossible to distinguish expected behaviour from buggy behaviour.
There are certain fringe groups out there who just really hate the concept of nullity for some reason, but as Ed points out, if you don't have null
or nil
then you'll just have to replace it with something else, which might lead to something worse than a crash (such as data corruption).
Many frameworks, in fact, embrace both concepts; for example, in .NET, a frequent pattern you'll see is a pair of methods, one prefixed by the word Try
(such as TryGetValue
). In the Try
case, the reference is set to its default value (usually null
), and in the other case, an exception is thrown. There's nothing wrong with either approach; both are used frequently in environments that support them.
It really all depends on the semantics. If null
is a valid return value, as in the general case of searching a collection, then return null
. On the other hand, if it is not a valid return value - for example, looking up a record using a primary key that came from your own database - then returning null
would be a bad idea because the caller won't be expecting it and probably won't check for it.
It's really very simple to figure out which semantic to use: Does it make any sense for the result of a function to be undefined? If so, you can return a null reference. If not, throw an exception.
Looking at your gists, it seems like regular old inheritance will do the trick, especially if you want to be able to process an instance of ShoppingCartWithContents in a method that only cares about the properties of ShoppingCart.
Best Answer
I suppose if you are immediately dereferencing the variable, you could debate either way, but I would still prefer the ArgumentNullException.
It is much more explicit about what is going on. The exception contains the name of the variable that was null, whereas a NullReferenceException does not. Particularly at the API level, an ArgumentNullException makes it clear that some caller did not honor the contract of a method, and the failure was not necessarily a random error or some deeper issue (though that may still be the case). You should fail early.
In addition, what are later maintainers more likely to do? Add the ArgumentNullException if they add code before the first dereference, or simply add the code and later on allow a NullReferenceException to be thrown?