How to use Maybe<T>
Before deciding to use Maybe<T>, have a think about whether it's for you while reading Should I use Maybe<T>?
Once you've decided, here's how to get started:
Creating a Maybe<T>
So you've decided to use Maybe<T>!
Use the following method to create a Maybe<T>:
Alternatively you can use an extension method:
The underlying type T of the Maybe can be inferred, so it need only be explicitly declared if you
need to ensure that a base class or interface is used. The creation method will also convert any
Nullable
The value, whether it's null or not, will be wrapped in a Maybe of the same
underlying type. Of course, Maybe<T> cannot be used for passthrough null-checking
in the same way as the Validate methods, because it changes the type of the parameter;
but using Maybe<T> more widely through a codebase can have its benefits too,
contributing to the overall robustness of the code. There's a further creation method that can be used in circumstances where there's
certainty that the value is not null: The value of using this method is semantic - it
allows that certainty to be expressed in the code, while maintaining compatibility with
other uses of Maybe<T>. However, if for some reason the value is actually null
against expectations, then an exception will be thrown. Converting back and forth between .NET nullable types and Maybe<T> is straightfoward;
any type T, including nullable value types and nullable reference types, can be converted to a
Maybe<T> using the extension method
ToMaybe()
; and a Maybe<T> can be converted to
a nullable type using the extension method
ToNullable()
[1],
[2]
. There are a number of methods on Maybe<T> for retrieving a value from it safely: Maybe<T> has a few more options for extracting values from it than Nullable<T> has,
but so far we've seen nothing much to distinguish Maybe from Nullable. The next few methods are
where that difference emerges. Some of these have supported aliases that may be more comfortable for
developers familar with the theory behind Maybes, but in writing Existential.Net I've tried to
emphasise usability over theory - so I'll mention the aliases here, then ignore them. Methods that act on a Maybe<T> and return a Maybe<TResult> can be chained together to apply a sequence of
operations, perhaps with the underlying datatype changing, without giving up the "Maybeness" of the results - so it's
not essential to know whether or not a value exists at any point when designing the sequence, reducing the amount
of conditional code that has to be written. Of course, that conditionality exists, but it's hidden away and dealt
with by the Maybe methods and doesn't intrude on the expression of more interesting business logic. (T and TResult
needn't be different types, but the possibility that they can be is what gives Maybe<T> its power.) There's an overload of DoEither that performs an Action without returning any values. It has its uses, but
it can only be used to terminate a sequence. IfExists is another method that can only be used to
end a sequence. The value in a Maybe<T> can be accessed and transformed using Linq syntax. In the following example Values from multiple Maybes can also be processed in a single Linq statement. In the following example
the values of two Maybe<string> are being transformed into a Maybe containing a tuple of ints.
If either of the string Maybes are empty, the tuple Maybe will also be empty - any empty value in a
sequence of operations will produce an empty result. The public void Method1(DerivedType inCouldBeNull)
{
// Declare a new Maybe:
var theMaybe1 = Maybe.WithValue(inCouldBeNull);
var theMaybe2 = inCouldBeNull.ToMaybe();
// When you need to specify the underlying type of the Maybe explicitly
// (for example if you want to use a base class or interface).
var theMaybe2 = Maybe.WithValue<BaseType>(inCouldBeNull);
}
public void Method2(DerivedType inCouldBeNull)
{
// Throws exception if value is null; a guarantee but at a cost.
// Can only be used when the type of the parameter is unambiguous.
var theMaybe3 = Maybe.WithKnownValue(inCouldBeNull);
// Throws exception if value is null; a guarantee but at a cost.
var theMaybe4 = Maybe<BaseType>.WithKnownValue(inCouldBeNull);
}
Converting between nullable types and Maybe<T>
Getting a value from Maybe<T>
Working with Maybes
Using Linq syntax with Maybes
from
is being used to refer to the value of theMaybe
(which is a Maybe<string>) and the
select
clause transforms it into a Maybe<int>. If the Maybe<string> is empty,
the result will be an empty Maybe<int>; so the "maybeness" is retained.Maybe<int> theResult = from theText in theMaybe
select theText.Length;
Maybe<(int, int)> theResult = from theText1 in theMaybe1
from theText2 in theMaybe2
select (Length1: theText1.Length, Length2: theText2.Length);
where
clause can also be used. In the example below, if theMaybe
contains
a string value that contains the search string, the length of the string value will be retuned as the
value of a Maybe<int>. If theMaybe
is empty, or the where
condition
is not satisfied, the Maybe<int> will be empty.Maybe<int> theResult = from theText in theMaybe
where theText.Contains("the search string")
select theText.Length;