Edit: As of C# 8, nullable reference types provide a functionally equivalent implementation of option types in a far more elegant way.

Option types have been in Java, Haskell and a lot of other languages for as long as I can remember, but sadly, they haven't officially made it to .NET yet.

I've been using Maybe<T>, my own implementation of an option type, in .NET for quite a while now, and have recently decided to turn it into a GitHub repository, mainly because I find myself copy pasting those two classes virtually every time I work on any WebAPI related project.

Without diving too deep in the null is a bad thing discussion, I'll outline what option types are, and why they may be useful when developing software in this post.

What is an option type, and why do we need them?

Simply but, an option type is a struct with two properties: HasValue and Value. An option type encapsulates either a value, or no value. The goal of the option type is to abstract null away, since, as outlined in the post above, the meaning of null is a rather ambiguous one.

The reason we "need" them is quite simple. Consider the following snippet:

What would happen if we suddenly decide we need the first element form this list, and we call .FirstOrDefault() to obtain that value? We'd get null. Null is the first item in the list, but we can't possibly know, it could also be returning default(string).

This is where option types come in: they either represent the value, or no value, but you're always certain which of the two.

Another example where option types would fit nicely into the BCL would be the various TryParse methods. For instance, int.TryParse(string value, out int result) returns a bool indicating whether the parsing operation succeeded, and passes the result back to the caller as an out parameter. With option types, we can do the following:

Want to know if the parsing operation succeeded? Check if HasValue is true. Instead of a return type indicating success combined with an out parameter indicating the value, we now have a single return type, and it says it all.

Isn't this the same as Nullable?

Yes, sort of. Nullable<T> is an option type, but unfortunately it only works on value types. It also gets a little bit of special treatment in the CLR in that it will never be boxed; either null is kept as a reference or the value of the nullable instance is kept, but never the nullable itself.

Oh, it's also directly assignable from T, which is something you can't achieve without the compiler really liking you either.

So null is always a bad thing?

Well, no, it doesn't have to be. You see, I started off this post mentioning that I don't want to dive into the whole "null is bad" debate, but I guess when discussing a solution to the "null problem" (I don't think null itself is a problem, by the way), you can't really keep your feet completely dry. I'll dip my toes a little.

In C#, null indicates a lack of value. That's great, because sometimes we need to indicate that we don't have a value. In the example above, we made a call to FirstOrDefault() which returned null, because it was the first value in the collection, but, as the caller, we can't really make out whether it returns default(T) or the actual first value.

Regardless of whether or not this is a situation you'll run in to very often, we can conclude that null does have a verbosity problem: it doesn't convey enough about what that null value you're seeing means. And that, in my opinion, is the problem option types solve.

Having said that, and adding to the ambiguity of null, this verbosity problem doesn't apply when properties or fields aren't set to an instance of their respective types. Given a property along the lines of:

public IComponentRepository ComponentRepository { get; set; }

null is very concise: ComponentRepository does not refer to an instance of an object, which is perfectly captured in a NullReferenceException. There are no two ways about it.


Option types, or Maybe<T> in my implementation, aim to solve a problem where null as a return value isn't concise enough.

Don't go about trying to abstract null out of the language completely. It has its place, but there are definitely occurrences where conveying a little bit more information would come in handy, and that's where we apply our option types.

Thanks for reading!