Let's Implement an Option Type in C#
Tags: csharp, dotnet, fluent, types
Published: 2020-03-25 17:39:28

---
title: Let's Implement an Option Type in C#
published: true
description: A simple implementation of an option type in C#
tags: #csharp #dotnet #fluent #types
---
> Note: The purpose of this post is to discuss a basic explanation, implementation and use of an Option type. It isn't to dive into more advanced functional programming topics like `Functor`, `Applicative` or `Monad`. I'm also not suggesting using options everywhere to model your domain. There are much better ways to model your domain using functional concepts. I highly recommend [Scott Wlaschin's Domain Driven Design talk] (https://fsharpforfunandprofit.com/ddd/) if you would like to learn more about the topic.

Many functional programming languages have a type called `Option` (F#, Scala, OCAML) or `Maybe` (Haskell, Elm, PureScript) as part of their core library. It allows the programmer to encode in the language's type system that data _may_ or _may not_ be present at run time. The compiler then becomes your friend and goes to work for you. It forces (or at least warns) the programmer to handle the case of when there is no data to operate on.

Let's jump into a quintessential example for the use of an Option type. Consider a function that does simple integer division. In C#, we might write something like:

```csharp
public static int IntDivide(int dividend, int divisor) =>
  dividend / divisor;
```

But what if the `divisor` is `0`? If we ran this method with `0` as the `divisor` we would get a `DivideByZeroException`.

Sure, we could throw an `ArgumentException` like so:

```csharp
public static int IntDivide(int dividend, int divisor) 
{
  if (divisor == 0)
    throw new ArgumentException("Cannot divide by 0.");
		
  return dividend / divisor;
}
```

A little better, but we still have the same problem - catching exceptions. It quickly becomes cumbersome to catch an exception every time we want to use our `IntDivide` method. What if we had a way to operate over data that could _perhaps_ be there or not at runtime, without using exceptions to indicate that we went down an invalid code path?

## Enter the Option Type
In F#, the Option type is defined like so:

```fsharp
type Option<'a> =
  | Some of 'a
  | None
```

If you're not familiar with F# syntax, you can think of the above union type definition like this: `Option` is a type that has only two possible cases. `Some` that encapsulates "some" data of a generic type `'a` and `None` representing no data at all.

If we were to write our `IntDivide` function in F# using an option type it would look something like this:

```fsharp
// int -> int -> int option
let intDivide dividend divisor =
  if divisor = 0
  then None
  else Some (dividend / divisor)
```

If the `divisor` is `0`, we are going to return `None` indicating that there isn't a result of dividing by `0` or `Some` with the value of the integer division "wrapped inside". 

Now any time we call the `intDivide` function, we as programmers must handle both cases of the `int option` or F# will give a warning that not all cases are matched:

```fsharp
let resultString =
  match intDivide 4 0 with
    | Some quotient -> sprintf "Matched Some case, quotient is: %d" quotient
    | None          -> "Matched None case because we divided by 0." 

printfn "%s" resultString
```

Can we implement similar behavior in C#? Absolutely!

## Implementation of Option in `C#`
C# doesn't have support for union types, but we can come fairly close. Let's define an interface with method called `Match` where we model the F# behavior above:

```csharp
interface IOption<T>
{
  TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
}
```

Now let's implement `Some` and `None` from our interface.

```csharp
class Some<T> : IOption<T>
{
  private T _data;
	
  private Some(T data)
  {
    _data = data;
  }

  public static IOption<T> Of(T data) => new Some<T>(data);

  public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
    onSome(_data);
}

class None<T> : IOption<T>
{
  public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
    onNone();
}
```
This interface method takes two `Func`s. The first `Func` is applied to the value that is encapsulated inside of the `Some` class. The second wraps a value of the same type as the result of the first `Func`, and is used for the `None` class.

Now to replicate the behavior we see above in F#, we can modify the C# `IntDivide` to look like:

```csharp
public static IOption<int> IntDivide(int dividend, int divisor) =>
  divisor == 0 ? new None<int>() : Some<int>.Of(dividend / divisor);

var resultString = 
  IntDivide(4, 0)
    .Match<string>(
       onSome: quotient => $"Matched Some case, quotient is: {quotient}",
       onNone: () => "Matched None case because we divided by 0."
    );
			
Console.WriteLine(resultString);
```

<hr style="display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;"></hr>

`Match` is a nice start, but it leaves a lot to be desired. What if we wanted to take our result and then divide it again using our `IntDivide` method? Well, since we are dealing with `IOption<int>` here, it would look something like this:

```csharp
IntDivide(10, 5)
  .Match(
    onSome: quotient1 =>
      IntDivide(quotient1, 2)
        .Match(
          onSome: quotient2 => quotient2,
          onNone: () => ??
	),
    onNone: () => ??
);
```

Yuck. Apart from the __Triangle of Doom__ code pattern we see beginning to emerge, we should also notice a couple of other concerns. First, what do we return when we are dividing by `0`? And worse, because of the way we wrote this code, we have to handle it _twice_. For our purposes well handle the `None` cases in a moment, but we are explicitly _forced_ to handle those cases in code instead of the error handling being exception driven. This should be seen as a __good__ thing! We have to make a decision about what to do when dividing by `0` in our code in order to get it to compile. 

Secondly, we should notice that we are doing a `Match` inside of a `Match`. Surely there must be a cleaner way to do this and lucky for us there is! `Bind`.

For `IOption`, you can think of `Bind` as a way to compose computations that also return `IOption`. This is exactly what we want with our `IntDivide` example, we want to be able to take the result from the first `IntDivide` and compose it with another call to `IntDivide`.

Let's add `Bind` to our `IOption` interface and then implement it for `None` and `Some`:

```csharp
interface IOption<T>
{
  TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
  IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
}

class Some<T> : IOption<T>
{
  private T _data;
	
  private Some(T data)
  {
    _data = data;
  }

  public static IOption<T> Of(T data) => new Some<T>(data);

  public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
    onSome(_data);

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data);
}

class None<T> : IOption<T>
{
  public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
    onNone();

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>();
}
```

Our ugly code above becomes:

```csharp
IntDivide(10, 5)
  .Bind(quotient => IntDivide(quotient, 2))
  .Match(
    onSome: Convert.ToDouble
    onNone: () => double.PositiveInfinity
  );
```

That looks much better and much more clean. We were able to implement a way to compose computations that also return `IOption` without having to do a nested `Match`. `Bind` takes a `Func` with the argument being the encapsulated result of the previous computation and it returns an `IOption`, the result of the composed computation.

But we also have another benefit as well. We were able to abstract way handling the `None` case until the end! We implemented a way that if any of our computations in our chain return an instance of `None`, then any computations afterwards won't be executed at all. 

For example, if we change our code above to: 

```csharp
IntDivide(10, 0)
  .Bind(quotient => IntDivide(quotient, 2))
  .Match(
    onSome: Convert.ToDouble
    onNone: () => double.PositiveInfinity
  );
```

We see that right way `IntDivide` is going to return an instance of `None` because we are dividing by `0`. `None`'s implementation for `Bind` is just to return a new instance of `None`, so the `Func` that we passed to `Bind` to do another `IntDivide` is ignored. We're able to create chains of computations that has the error handling built into it, and we can choose what to do if any computation along the way yields `None` until the end of our chain of computations!

Great! But let's keep adding to our toolbox. Not everything that we want to work with is going to return an `IOption`. What about an operation like adding? Adding integers is pretty straightforward, in the majority of use cases there isn't a need to return an `IOption`.

```csharp
public static int IntAdd(int a, int b) => a + b;
```

It seems kind of silly to do something like this since we aren't ever going to encounter a `None` case from the computation passed to `Bind`:

```csharp
IntDivide(10, 5).Bind(quotient => Some<int>.Of(IntAdd(quotient, 3)));
```

So let's add a method to our interface to handle cases where we want to work with computations that themselves don't return `IOption`. We're going to call it `Map` and implement it for `Some` and `None`.

```csharp
interface IOption<T>
{
  TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
  IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
  IOption<TResult> Map<TResult>(Func<T, TResult> f);
}

class Some<T> : IOption<T>
{
  private T _data;
	
  private Some(T data)
  {
    _data = data;
  }

  public static IOption<T> Of(T data) => new Some<T>(data);

  public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
    onSome(_data);

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data);

  public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(_data));
}

class None<T> : IOption<T>
{
  public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
    onNone();

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>();

  public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new None<TResult>();
}
```

Now let's use `Map` in our example we've been working with:

```csharp
IntDivide(10, 5)
  .Bind(quotient => IntDivide(quotient, 2))
  .Map(quotient => IntAdd(quotient, 3))
  .Match(
    onSome: Convert.ToDouble
    onNone: () => double.PositiveInfinity
  );
```

We've created a Method called `Map` that takes a `Func` where its argument is the result of the computation before it and it's result is a type that isn't `IOption`, in this case `int`. Looking at the implementations of `Some` and `None` for `Map`, we see we get the same error handling benefits we did with `Bind`. If the computation before it is an instance of `None`, return a new instance of `None`, otherwise apply the `Func` to `_data` inside of `Some` and create a new instance of `Some` from it's result.

<hr style="display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;"></hr>

I've intentionally ignored dicussing what the result should be if we match the `None` case at the end until now. For our purposes, it illustrates the point of `Match` to return `PositiveInfinity` if we divide by `0`, otherwise convert the `int` wrapped inside the option to a `double` and return the `double`.

In the real world, returning `PositiveInfinity` for the `None` case most likely isn't what is going to happen. But the choice is up to you! If this is an API, maybe you decide you're API isn't going to accept divisors of `0` and you return a Bad Request to indicate that. Or maybe at the end of our chain, you decide that dividing by `0` truly is an exceptional case and you throw an exception. That choice is on the programmer, but what's great here is that you are __required__ to make that choice by the compiler. This is going to lead to less bugs because you're forced to think about what to do when you do get a `None`. 

<hr style="display: block;
    height: 1px;
    border: 0;
    border-top: 1px solid #ccc;
    margin: 1em 0;
    padding: 0;"></hr>

Let's implement one more method for `IOption`. Often times when working with options, we just want the value "wrapped inside" of the option or some other value if the option is `None`. It can become a little tiresome to write out `Match` for these situations. Let's implement a method called `Or` on our `IOption` interface to make these situations easier on ourselves. This is going to give us the value encapsulated inside `Some` or the default value you pass to `Or` on `None`.

```csharp
interface IOption<T>
{
  TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> onNone);
  IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f);
  IOption<TResult> Map<TResult>(Func<T, TResult> f);
  T Or(T aDefault);
}

class Some<T> : IOption<T>
{
  private T _data;
	
  private Some(T data)
  {
    _data = data;
  }

  public static IOption<T> Of(T data) => new Some<T>(data);

  public TResult Match<TResult>(Func<T, TResult> onSome, Func<TResult> _) =>
    onSome(_data);

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => f(_data);

  public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new Some<TResult>(f(_data));

  public T Or(T _) => _data;
}

class None<T> : IOption<T>
{
  public TResult Match<TResult>(Func<T, TResult> _, Func<TResult> onNone) =>
    onNone();

  public IOption<TResult> Bind<TResult>(Func<T, IOption<TResult>> f) => new None<TResult>();

  public IOption<TResult> Map<TResult>(Func<T, TResult> f) => new None<TResult>();

  public T Or(T aDefault) => aDefault;
}
```

We can finally write our example in a nice fluent way:

```csharp
IntDivide(10, 5)
  .Bind(quotient => IntDivide(quotient, 2))
  .Map(quotient => IntAdd(quotient, 3))
  .Map(Convert.ToDouble)
  .Or(double.PositiveInfinity);
```

If you'd like to see more C# option code, including a helper classes that leverages options for operations like trying to find elements in a dictionary, I've created a [Gist](https://gist.github.com/ntreu14/72e56ea8273df854cca8fad7502f7b60) to explore that code if you'd like.

Thanks for reading!