Either type, also called
Choice in F# parlance, is a way of representing a value that can be either one of two types. This can be extremely useful. For example, retrieving a date of birth from a textbox could be expressed as
Either<ParseException, DateTime>. In other words, the result is a value that is either a valid
DateTime, or is a
Being a hasty introduction this post is not going to do justice to how useful this type is, but hopefully some of its goodness will shine through despite my rambling prose. :)
In .NET we don’t need to implement this ourselves. We can use F#’s
Choice type from any .NET language including C# using the same steps as for
Option, or use
Either from the Sasa library1. I think it’s useful to look at how we could implement this ourselves though, so here goes…
It’s a bit clumsy to represent in C#, but here’s one implementation:
F# makes things much easier:
Both implementations show two main points about
- It has two generic parameters
- We can construct an
Eitherthat has a value of the first type, or a value of the second type, but not both.
Accessing either value
We’ve seen the basic
Either structure, but so far have no way to use it. Everything we need to do with
Either we can do by adding this function2:
If we have an
Either<ParseException, DateTime> this will let us handle both cases.
We can implement a number of helpful functions that make dealing with
Either values really convenient.
Because we are accurately communicating to people that a method can return two different types of results, or takes a value as an argument that can be one of two types. Importantly, we’re also telling the compiler exactly what the possible values are, so it will tell us if we’re not handling any cases.
Fold and similar functions to use either value in very convenient, low friction ways. The only times it causes me any pain is when I’ve completely overlooked a possibility in my code, and the compiler keeps me honest and makes me handle the case. I much prefer this to getting a bug report or having silently failing code.
Sticking with our
Either<ParseException, DateTime> example, there is no way we can forget to handle the possibility our code could fail to parse out a
DateTime. If we used a traditional exception we’re relying on there being documentation, people reading that documentation, and people never making a mistaek.3
An unexceptional example
Either to represent operations that can potentially fail is a convenient example, but we don’t need to restrict its use to those cases. One example that came up on the NSubstitute mailing list was dealing with values that could be partially or fully loaded. Rather than relying on a boolean flag to indicate a load state (and hoping everyone remembers to check it before accessing unloaded fields), we can use something like
If we need to display the person’s name, regardless of whether the
Person has been fully loaded, we can easily extract the information we need:
At some point we need to ensure the full entity is loaded, which we can express like this:
Either type lets us represent a value that can be one of two possible types. By using this as a return type or argument type, we communicate to readers and the compiler that there are two possibilities, which ensures we do not accidentally forget to handle particular cases. Using
Fold and related functions gives us really convenient, low-friction ways of using, transforming and combining these values. I can’t really see a downside to using this type (please comment if you can. Normally not seeing negatives to something means I don’t understand it sufficiently).