Skip to content

Option User Guide

Martin Marciniszyn Mehringer edited this page Apr 3, 2019 · 19 revisions

User Guide for Option<T> and Maybe<T>

This guide describes the programming interface of Option<T> and Maybe<T>. An executable version of the code presented below can be found in OptionDemo.

Comparing Option<T> to T?

Option<T> and Maybe<T> provide essentially the same programming interface as Nullable<T> (T? for short), but allow T to be either any type or a class type, respectively.

Initialization

Just like T?, Option<T> can be initialized with null, default, or any valid value of type T:

double? nullDouble = null;
Option<string> nullString = null;
double? someDouble = 3.14;
Option<string> someString = "foo";

Basic Methods

We introduce a Print helper function so as to keep the code examples concise:

static void Print(object value = default) => Console.WriteLine(value);

We can check the presence of a valid value with HasValue:

Print(nullDouble.HasValue); // False
Print(nullString.HasValue); // False
Print(someDouble.HasValue); // True
Print(someString.HasValue); // True

We employ another helper function for dealing with exceptions:

static object TryCatch<T>(Func<T> func)
{
    try { return func(); } catch (Exception ex) { return $"{ex.GetType()}: {ex.Message}"; }
}

Property Value provides direct access to the value stored in Option<T>:

Print(someDouble.Value);                 // 3.14
Print(someString.Value);                 // foo
Print(TryCatch(() => nullDouble.Value)); // System.InvalidOperationException: Nullable object must have a value.
Print(TryCatch(() => nullString.Value)); // System.InvalidOperationException: Nullable object must have a value.

One can also access the value with an explicit cast:

Print((double)someDouble);                 // 3.14
Print((string)someString);                 // foo
Print(TryCatch(() => (double)nullDouble)); // System.InvalidOperationException: Nullable object must have a value.
Print(TryCatch(() => (string)nullString)); // System.InvalidOperationException: Nullable object must have a value.

Access the value or return default(T) using method GetValueOrDefault():

Print(nullDouble.GetValueOrDefault()); // 0
Print(nullString.GetValueOrDefault()); //
Print(someDouble.GetValueOrDefault()); // 3.14
Print(someString.GetValueOrDefault()); // foo

Or provide a custom default value:

Print(nullDouble.GetValueOrDefault(42));    // 42
Print(nullString.GetValueOrDefault("bar")); // bar
Print(someDouble.GetValueOrDefault(42));    // 3.14
Print(someString.GetValueOrDefault("bar")); // foo

Null Coalescing Operator

The null coalescing operator (??) is not directly supported on Option<T>. Instead, we call the method GetValueOr(Func<T>). That is, we provide a function that can supply a default value similar to this one:

static T Computation<T>(T value)
{
    Print("running computation ...");
    return value;
}

We can use it in GetValueOr(Func<T>) like so:

Print(nullDouble ?? Computation(42.0));                 // running computation ... 42
Print(nullString.GetValueOr(() => Computation("bar"))); // running computation ... bar
Print(someDouble ?? Computation(42.0));                 // 3.14
Print(someString.GetValueOr(() => Computation("bar"))); // foo

We can use the same construct to throw custom exceptions when there is no valid value:

Print(TryCatch(() => nullDouble ?? throw new Exception("missing double")));                // System.Exception: missing double
Print(TryCatch(() => nullString.GetValueOr(() => throw new Exception("missing string")))); // System.Exception: missing string
Print(TryCatch(() => someDouble ?? throw new Exception("missing double")));                // 3.14
Print(TryCatch(() => someString.GetValueOr(() => throw new Exception("missing string"))))  // foo

Reducing the Memory Footprint with Maybe<T>

Programming Examples

Clone this wiki locally