Null Object design pattern and Maybe Monad in C#
In most functional languages you cannot get a null reference exception. If you really need to represent a state of Something or Nothing then the Option type is a built in type. In C# 6 in an attempt to solve the null problem the operators “?.” and “??” (is called the null-coalescing operator) where introduced.
Null Object Design pattern
A more elegant solution to the problem of Null is the “Null Object” design pattern. The null object pattern is a spacial case of the strategy pattern.
Here instead of setting something as null we can set it as NullObject. Were NullObject methods are empty or they don’t have any effect.
This has many disadvantages one of them is having to create different Null Objects for each Real Object that could be null.
Extending Nullable <T>
We can extend the Nullable<T> with a Map method that would only apply a function Func<T, T1> when the nullable has a value.
This is a nice solution but unfortunately until C# 8 there was no support of Nullable Reference Types that’s why there is this where T : struct constraint on the generic. So, there is no way to actually provide a unifying abstraction for both Reference and Value types for now. That’s why we have to create a new Maybe type that is like the Nullable but allows for the support of Refence types. Also the Maybe pushes a Functional way to write your code without the need for using the .HasValue or the ?. (null conditional operator) and generally the whole syntax of trying to avoid null in an imperative way. We cannot avoid the checking but why not encapsulate it inside the Map, Bind etc and stop spreading irrelevant cross cutting concerns like null checking throughout the codebase?
The Functional equivalent — Maybe as Functor
Now the Maybe functor idea takes this line of reasoning one step further, by abstracting the null Object mechanism inside a functor. Thus, instead of applying the objects on functions, we reverse the flow by applying the functions onto objects. Now, we can isolate the effect inside a single point; the “map.”
After all this discussion, hopefully, the implementation of maybe functor would be apparent
Maybe MatchWith implementation for Maybe is straightforward. Since it is a coproduct, we have to implement for each subtype the MatchWith, and we are going to call different callbacks, so we can distinguish (pattern match) between Some and None.
Run This: .Net Fiddle
Now let us revisit the problem of fetching a client asynchronously with a certain Id from a repository.
Functional Libraries :---Language-Ext- Option
There is an explicit implementation of Option monad that can’t be used with null values
Maybe Monad
Maybe monad is extension of the Maybe Functor. In order to make this maybe functor implementation into a Monad we must provide a bind method that combines two Maybe monads into one. There are 4 different ways to combine the 2 possible states of maybe (some,none) one can see that a valid implementation would be the following :
Run This: .Net Fiddle
the only combination that leads to a new some (_) is when the two paths that both have values are being combined.
Some (x). Bind ( None )
None ( ). Bind ( Some )
Some (x). Bind ( Some ) //only this gives a some result
None ( ). Bind ( None )