Null Reference Handling – Requiring Explicit Null Reference Handling in C#

apicnull

One of the problems I have with null references is that they may not be exceptional. In my current position, there are few requirements and you are lucky if conventions are followed. This means being unable to handle a request is a frequent occurrence and throwing an exception is too slow (think millions of requests). I am in charge of writing an api for handling these requests and I am trying to decide how to handle failures.

Our code is written in C# and I am a huge fan of LINQ. I know that LINQ handles this problem by providing two methods "Function()" and "FunctionOrDefault()". By returning the default value (usually null), we make it very easy for the developer to shoot himself in the foot. On the other hand, throwing an exception is unacceptable for us. There is also the "TryParse" pattern, but that doesn't lend its self well to lambda expressions.

I recently discovered the Option type in F# and how it requires explicit handling of both the Some and None cases or your assembly will not compile. This seems like a much better solution to the null value problem than leaving it up to the developer to remember to implement error handling.

I could implement an option type that will not both compile and return the desired value unless both Some and None cases are handled. The contract for my implementation would look like this:

Option<SomeClass> option = new SomeClass { Value = 5 }.ToOption(); // Extension method
int value = option.Some(x => x.Value).None(x => x.Default(25)); // Other helper methods provided as well for None cases.

So my question is, if I have the ability to require explicit null reference handling, are there any downsides to this approach? Would it be better to stick with conventions rather than try to solve this problem upfront to prevent future hidden bugs?

Best Answer

You don't need it. Here's my reasoning:

  1. You may be underestimating the consumers of your API. Every textbook I ever read on programming languages contained a section on how to check for null values. Many languages include null coalescing or null checking features + syntactic sugar.

  2. You need to prove to me (another programmer) why you need this convention.
    If you can't prove that it provides a significant workflow or debugging benefit, then you need to use a simpler approach. Especially if the simpler approach is already taught by the community at large.

    var value = proxy.FirstOrDefault();
    if (value != null) { ...
    
  3. Consider is the meaningfulness of the idioms you create. Is the code above more or less meaningful than your ToOption() method? If they are about the same, don't do it. Only do work that provides a significant benefit. This is the basic idea behind YAGNI.

  4. Consider a similar debate in the nodejs community about the usefulness of enforcing the Promise/A pattern for libraries. While not equivalent, you can see that there is some discontinuity on the issue.

  5. Lastly, I would err on the side of allowing your consumers to choose the level of complexity they want. If your ToOption approach is clearly superior, consumers will implement it anyway.

Related Topic