Friday, October 24, 2008

Null propagation in C#

Have you ever wished that there was as an operator in C# that would allow you to evaluate expression to null if null was used anywhere in expression. This can be very useful, for example when creating code generation templates. So instead of having to test each member for null one could write something like

person!address!street

which would evaluate to null if person or address were null. This allows you to write concise short code.

Unfortunately C# does not have such operator, and does not allow creation of new operators. So what can we do?
Well, enter the world on Monads. Here is a solution to the problem, not as nice as above operator but still is workable. This solution would allow you to write code like this

preson.NullSafe(p=>p.address).NullSafe(a=>a.street)

This is still better then having to test person and address for null value.
So how is this achieved?

Solution combines theory of Monads with C# 3.0 such as:
• extension method
• lambda expressions 
• anonymous methods
• type inference

First we will crate a monadic container that will contain value (instance of object) or missing value (null). This type of monad is called Maybe. Here is the implementation of the Maybe type.
public class Maybe
{
   public readonly static Maybe Nothing = new Maybe();

   public T Value
   {
       get;
       private set;
   }
   public bool HasValue
   {
       get;
       private set;
   }
   public Maybe()
   {
       HasValue = false;
   }
    public Maybe(T value)
    {
       Value = value;
       HasValue = true;
    }
 }
Next we will create extension method for any type T, that will allow us to convert any type into Maybe monad. This function is referred in Monad theory as Unit function and its job is to take input value and return instance of the Maybe type. Here is the implementation of this method:
//extension method for any type that wraps T into Maybe
//Unit function
public static Maybe ToMaybe(this T value)
{
   if (value == null)
   {
     return new Maybe();
   }
   return new Maybe(value);
}

Now that we have instance of the Maybe type, we need a way to unwrap the value and invoke delegate with the unwrapped value (bind function). Meet “GetMember” extension method for Maybe type:
//Bind function
public static U GetMember(this Maybe m, Func k) 
{
   if (!m.HasValue)
   {
     return default(U);
   }
   return k(m.Value);
}
As of this point we have everything we need to write null safe member access:

var value =ps.ToMaybe().GetMember(p=>p.Address.ToMaybe().GetMember(a=>a.ZipCode));

Although this code works it is very verbose and not easy to read. So we are going to create a one more extension method for any type T, that will wrap above two methods creating friendlier syntax.
      
//wrapper 
public static U NullSafe(this T m, Func k) 
{
   return m.ToMaybe().GetMember(k);
}
public static void NullSafe(this T m, Action a) 
{
   var temp = m.ToMaybe();
   if (temp.HasValue)
 {
      a.Invoke(temp.Value);
   }
}

Now finally we can write a code seen at the beginning of the document.
var value3 = ps.NullSafe(p => p.Adress).NullSafe(a=>a.Street);

I’ve tested in multiple scenarios and it wored fine, but it has not gone through rigourous testing.
Let me know if you find any problems with this.