Skip to content
David Arno edited this page Mar 8, 2017 · 4 revisions

Option<T>

SuccincT.Options.Option<T>

Provides an optional value of type T. Modelled on F# options. Either contains a T value, or none.


Construction

Instances of Option<T> cannot be created directly. Instead they can be created via one of two means:

  1. Use the two static methods Option<T>.None() and Option<T>.Some(T value) to create a none or some value, respectively.
  2. A value of T can be directly used to create a "some value" option, eg:
Option<int> o = 1;

creates o as an option containing the value, 1.

Equality

Whilst Option<T> is a class, not a struct, it overrides both Equals and the == & != operator pair to provide value-based equality, as demonstrated by the following code:

var a = Option<int>.Some(1);
var b = Option<int>.Some(1);
var c = Option<int>.Some(2);
var d = Option<int>.None();
var e = Option<int>.None();

// The following expressions are all true
a == a
a == b
a != c
d == e
a.Equals(b)
d.Equals(e)

Functional Use

Option<T> uses Succinc<T>'s pattern matching capabilities to perform an action or generate a result according to its value. Two versions of the match method are directly supported by Option<T>:

Match()

    public OptionMatcher<T> Match()

Match() supports the construction of pattern matches and actions (void methods) to invoke upon match. The pattern must be terminated with Exec().

The format of an option match pattern is as follows:

option.Match()
      .Some()<optional guard>.Do(value => action on value)
      .None().Do(() => action on no value)
      [.Else(option => action on option when no match) |
       .IgnoreElse()]
      .Exec()

Some() can take an optional guard of two forms:

.Some().Of(value1).Or(value2).Or(value3)...Do(value => action on value)
.Some().Where(value => boolean expression).Do(value => action on value)

Multiple Some() expressions may be defined. Each is compared in turn again the value (assume there is one) until a match is found. The action is then invoked and no further matching occurs.

Multiple None() expressions can be defined, but - as None has no value, the first will match if the option has no value and so subsequent definitions, and associated actions, will always be ignored.

The Else action is used if no match was found. The option itself is passed as a parameter to the associated action. If no action is required when no match occurs, IgnoreElse can be used instead.

If no match is found, and no Else() or IgnoreElse is defined, a SuccincT.PatternMatchers.NoMatchException will be thrown

Match<TResult>()

    public OptionMatcher<T, TResult> Match<T>()

Match<T>() supports the construction of pattern matches and functions returning a TResult to invoke upon match. The pattern must be terminated with Result().

The format of an option match pattern is as follows:

option.Match<T>()
      .Some()<optional guard>.Do(value => func resulting in a T)
      .None().Do(() => func resulting in a T)
      .Else(option => no match func resulting in a T)
      .Result()

Some() can take an optional guard of two forms:

.Some().Of(value1).Or(value2).Or(value3)...Do(value => func resulting in a T)
.Some().Where(value => boolean expression).Do(value => func resulting in a T)

Multiple Some() expressions may be defined. Each is compared in turn again the value (assume there is one) until a match is found. The function is then invoked and no further matching occurs.

Multiple None() expressions can be defined, but - as None has no value, the first will match if the option has no value and so subsequent definitions, and associated functions, will always be ignored.

The Else function is used if no match was found. The option itself is passed as a parameter to the associated function.

If no match is found, and no Else() defined, a SuccincT.PatternMatchers.NoMatchException will be thrown

For further details see the pattern matching options guide.

Imperative Use

As an alternative to using an option in a functional style, its value can be directly accessed by more traditional, imperative style C# code. Two read-only properties are provided for this purpose:

HasValue

public bool HasValue { get; }

True if the option has a value; else false.

Value

public T Value { get; }

If HasValue is true, this will return the value held by the option. Otherwise an InvalidOperationException will be thrown.

Extensions

Option<T> provides a number of extension methods for manipulating the value, if present.

Choose<T>

public static IEnumerable<T> Choose<T>(this IEnumerable<Option<T>> options)

Returns a new enumeration of options containing just those with a value. Equivalent to executing:

from option in options where option.HasValue select option;

Flattern<T>

public static Option<T> Flatten<T>(this Option<Option<T>> option)

"Flatterns" (or de-nests) an option of option of T.

For an Option<Option<T>> with none, an Option<T> with none is returned.

For an Option<Option<T>> with a value, an Option<T> with that same value is returned.

Map<TInput, TOutput>()

public static Option<TOutput> Map<TInput, TOutput>(this Option<TInput> input,
                                                   Func<TInput, TOutput> f)

Maps the input option to an output option, via the supplied function.

For an Option<TInput> with none, an Option<TOutput> with none is returned.

For an Option<TInput> with a value, an Option<TOutput> with the result of applying f(input.Value) to that value, is returned.

Or<T>()

public static Option<T> Or<T>(this Option<T> option, Option<T> anotherOption)

Returns option if it has a value, otherwise anotherOption is returned.

public static Option<T> Or<T>(this Option<T> option, 
                              Func<Option<T>> lazyAnotherOption)

Returns option if it has a value, otherwise lazyAnotherOption() is called, and the result of that function is returned.

Finally, a number of extension methods for IEnumerable<T>, IDictionary<T> and for handling casting and null in general types are provided. See Extension methods for existing types, which use Option<T> for details.