Step by step implementation of Option type in C#

Option type is widely used in functional programming languages such as Haskell, F# and Scala. It is conventional to return an option value if a function can fail. For example, the following parseInt parses the given string into an integer. Because parseInt can fail when the input string is malformed, it returns int option instead of int. The return value is either Some(i) or None.

let parseInt intStr =
    try
        let i = System.Int32.Parse intStr
        Some(i)
    with _ -> None

The caller of the function must perform pattern matching on the option value and handle both cases explicitly.

let parseIntWithDefault v def = 
    match parseInt v with
    | Some i -> i
    | None -> def

C# does not provide an Option type, but we can emulate it with the help of C# generics and delegates. Let’s start with the abstract base class Option.

    public abstract class Option<T>
    {
        public abstract T Value { get; }
        public abstract bool IsSome { get; }
        public abstract bool IsNone { get; }
    }

Value property returns the underlying value of type T. IsSome and IsNone properties return a boolean flag to indicate whether this value is Some or None.

Option has two subclasses: Some and None. Both classes are sealed because we don’t want these classes to be extended. This is how we cruelly emulate algebraic data type in C#.

    public sealed class None<T> : Option<T>
    {
        public override T Value
        {
            get { throw new System.NotSupportedException("There is no value"); }
        }

        public override bool IsSome { get { return false; } }
        public override bool IsNone { get { return true; } }
    }

    public sealed class Some<T> : Option<T>
    {
        private T value;

        public Some(T value)
        {
            if (value == null)
            {
                throw new System.ArgumentNullException("value", "Some value was null, use None instead");
            }

            this.value = value;
        }

        public override T Value { get { return value; } }
        public override bool IsSome { get { return true; } }
        public override bool IsNone { get { return false; } }
    }

The implementation is trivial. Value property of None throws an exception because there is no value to return. The constructor of Some throws an exception when the input parameter is null because Some is never null.

The caller can use Option type as in the following:

var v = new Some<int>(0);
if (v.IsSome)
    System.Console.WriteLine(v.Value);
else
    System.Console.WriteLine("None");

This code looks okay at first, but we’ve just lost the power of pattern matching. We no longer can force the caller to handle both Some and None cases. The caller can easily ignore to check IsSome property and just retrieve the underlying value with Value property.

To fix this problem, let’s emulate pattern matching in C# with Match method.

    public abstract class Option<T>
    {
        // Other methods ...
        public abstract TResult Match<TResult>(Func<T, TResult> someFunc, Func<TResult> noneFunc);
    }

Match takes two delegates which handle each case respectively.

    public sealed class None<T> : Option<T>
    {
        // Other methods ...
        public override TResult Match<TResult>(Func<T, TResult> someFunc, Func<TResult> noneFunc)
        {
            return noneFunc();
        }
    }

    public sealed class Some<T> : Option<T>
    {
        // Other methods ...
        public override TResult Match<TResult>(Func<T, TResult> someFunc, Func<TResult> noneFunc)
        {
            return someFunc(value);
        }
    }

With Match method, the caller must pass delegates to handle both Some and None cases explicitly.

var v = new Some<int>(0);
var str = v.Match(
    v  => v.ToString(),
    () => "None"
);
Console.WriteLine(str);

Other methods of Option such as Fold and Map can be easily added. See Option.cs for the full source code with Map method added.

This is just a proof-of-concept implementation. Please refer to Functional C# if you are looking for a full featured functional programming library for C#.

Advertisements

4 thoughts on “Step by step implementation of Option type in C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s