With functional programming on the rise nowadays,
more and more people start using functional
patterns in their code.
One of the simplest patterns is
Maybe<T>’s primary use case is to represent a possibly
I have already use
Maybe<T> a few times in real
codebases and in this post I want to gather my thoughts
Maybe<T> and how, I think, it should be used.
Why we use
Most people that use
Maybe<T> generally fall into
one of the two categories.
Category 1: Wants to eliminate
For a long time before
Maybe<T> programmers tried to
clearly state to the clients of their API that a given
method may return
null instead of an object.
Some of them used special naming conventions or
comments, for example:
Others resorted to using special marking attributes and static code analysis tools. A good example of this category is JetBrains.Annotations package, that can be used together with ReSharper to detect missing null checks:
Yet another solution to this problem were Code Contracts developed by Microsoft.
None of those solutions is perfect and
to offer a better alternative.
Why? Because it is checked by the compiler,
does not require additional tools and does not slow
But remember there is
no silver bullet,
Maybe<T> is not perfect either.
We can use
Maybe<T> like this:
If you find yourself in this category of programmers, you would definitely want to use a lightweight library that does not force you to embrace a more functional style. One good library that I can recommend is: CSharpFunctionalExtensions.
If you choose a different library, please make sure to check
Maybe<T> is implemented using
struct, otherwise you
may be surprised:
One small downside of using a
possibility of declaration of a nullable
When I was writing this article I tried to gather some
best practices of using
Unfortunately it was very difficult to provide a comprehensive
list. There is not much material on this on the web (I mean using
Maybe<T> not in the FP fashion) and the available
material is often contradictory.
And so instead of providing you with a list of best practices,
I will only give you some hints where you can look for advice.
We should start our search by looking at
Java 8, which was published in 2014 and introduced
The purpose of this class is to be a nullability marker
for method results just like our
There are a lot of articles about how
and should not be used.
A good starting point will be
this SO question
with the first two answers.
From this question alone we may learn e.g. to never wrap
a collection into
instead of we should return a possibly empty collection.
The downside of reading Java’s best practices is that some of them do not apply to C#. For example let’s look at the advice given in this SO answer:
When a method can accept optional parameters, it’s preferable to adopt the well-proven approach and design such case using method overloading.
In other words author suggest to change:
But this argument does not applies to C#, where we can use implicit conversion operator with default parameters to achieve exactly the same effect without using overloads:
As we can see every Java’ish advice must be taken with a grain of salt.
Fortunately for us there is more and more C# posts about
Maybe<T>. For example this one
from the author of CSharpFunctionalExtensions library.
Although I cannot provide you with a list of best practices,
I think I have gathered enough experience to provide
you with a list of
Maybe<T> code smells:
Maybes are wrong, for example
Maybe<Maybe<string>>. Usually this is a sign that you should replace one of
Mapcalls by a
Maybes that wrap collections are wrong, for example
Maybe<List<User>>. Instead return a non-empty or empty collection.
Maybes wrapping nullable types are wrong, for example
Maybe<int?>. Instead convert nullable type
Maybe<T>. Even if you chosen library does not support such conversion out of the box, you may write an extension method that provides this functionality yourself:
- Nested callbacks when using
Maybe<T>fluent interface are wrong. For example:
Also be mindful when using
Maybe<T> with properties.
A declaration like:
Means that you may both get and set an optional value.
In other words assignment of
None value to this
property should be valid:
A property that can return
None but must be
set to some value should be split into a getter and a method:
As you probably heard C# 8.0 is going to introduce a nullable reference types (NRT).
Will NRT replace
For “Category 1” programmers, NRTs offer a better
Maybe<T>. On the other hand a lot of people
that start in “Category 1”, slowly begin to embrace more FP approach.
Usually people start by using
Maybe<T> fluent interface to transform
Maybe<T> value into another. After some time they take a leap and
switch to writing in a more functional fashion.
We may also take a look at Kotlin,
a language created by JetBrains that from the very beginning
offered nullable reference types.
And yet the most popular Kotlin functional library
still offers an
So it looks like NRT or not,
Maybe<T> is going to stay with us for sure.
Category 2: Wants to embrace FP paradigm
Programmers belonging to this category embraced FP. They often think about using F# at work and are a bit disappointed by poor C# pattern matching facilities.
Code written in FP fashion will never use
if to check
Maybe<T> contains some value, instead a fluent interface
will be used to transform
Maybe<T>s into some other values, for example:
Alternatively we may change our previous method to:
The only difference between these two methods
is the value returned for users not present in the repository.
GetUserCulture returns for them
returns a default culture (
Another sign of a functional design, is that monads like
will be unpacked only on the outskirts of the application.
For example in a typical RESTful service,
Maybe<T> value will
be unpacked only in the controller:
In this category of programmers there is also a small group of zealots, that in my opinion go a little bit to far in their cult of monads. They propose to use LINQ query syntax to transform monads. Let my explain this using an example:
I must admin that LINQ query offers some advantages like
ability to use
where keywords. Also some transformations
may be easier to express using LINQ query syntax, for example:
Yet in my opinion fluent interface is in 90% of cases
a more readable and understandable way
Maybe<T>s and other monads.
For example we may rewrite the last code snippet to:
Not as pretty as LINQ query but still readable.
At the end of the day consistency is what matters on real projects. Choose one style and follow it consistently.
In this category we find libraries like LanguageExt. This library has many flaws but still it is the best functional library on the market. My biggest disappointment with LanguageExt is poor documentation, which basically consists of just a list of functions without any guidelines how this library should be used and how it affects overall architecture. Compare this with Vavr (the most popular FP library for JVM) and you can clearly see the difference.
If you decided that you want to use FP in you code, you should definitively check awesome Railway oriented programming talk.
Maybe<T> is not the only monad that is popular, other
frequently used one is
Either<L,R> is used to represent either a result of computation or an error.
You may think of
Either<L,R> as a functional response to exceptions.
If you want to use
Maybe<T> efficiently, you must learn
how it can be transformed it into other monads, in particular into
E.g. we may make our last example more robust if we provide
information to the user why the computation failed:
Since FP is on the rise, you will find a lot of books, blogs, podcasts and MOOC’s about using FP in C#. Also .NET has amazing F# community that is very welcoming to the beginners. One of the best blogs about FP in C# is in my opinion Mark Seemann blog.
What to do with None?
How much value you will be able to extract from
Maybe<T> depends on
your attitude towards
Every time when you have to handle
None, you must decide if it is
the result of
the accidental complexity
e.g. someone passed a wrong id to the REST API)
or if you just discovered a new edge case in your domain.
To better understand the problem let’s follow an imaginary example.
Joe must write a simple function that will
send an email message to all users whose subscriptions will end in the next month.
During implementation Joe notices that
EmailAddress field in
is declared as
Now Joe knows that for some strange reason not all users have email addresses. Joe logs into production DB to confirm that some email addresses are missing and indeed they are. Looks like Joe just discovered a new edge case. Joe goes to Mark a business analyst to describe the problem. Mark is a long timer in the company and knows that for a short period of time users were able to log into the platform using their phone numbers instead of emails. A new solution is created. Users that have no email address will receive a text message instead of an email. Also users without email will be asked to enter their email address next time they log into the platform. Success!
On the other hand consider what will happen if Joe just
dig out the email address from
Maybe<T> by accessing
Value or if he just
log a warning about missing email address
without telling anyone from the business side?
End of the part I
Soon I will write a follow up to this post in which
we will try to implement a perfect
Maybe<T> type on our own and we will see
that it is not an easy task in C#.