Software Programming

Kunuk Nykjaer

Monads for C# – tool for cleaner code

with one comment


Tedious codes

You want to extract a phone number from a data source.

 

Do you ever write code like this?


Building building = GetBuildingFromSomeSource();            
string phone = null;
if (building != null && building.Manager != null && building.Manager.ContactInfo != null)
{
    phone = building.Manager.ContactInfo.PhoneNumber;
}

All those null checks can be tedious. And the code doesn’t look ‘clean’

 

Here’s is an alternative method of the same idea.

var phone = building == null
    ? null
    : (building.Manager == null
        ? null
        : (building.Manager.ContactInfo == null
            ? null
            : building.Manager.ContactInfo.PhoneNumber));

The code still looks tedious.

 

Here’s another alternative method of same idea.

var phone = building != null 
    && building.Manager != null 
    && building.Manager.ContactInfo != null 
        ? building.Manager.ContactInfo.PhoneNumber 
        : null;

Still looks pretty tedious.

 

Naïve

What if you just write like this.

var phone = building.Manager.ContactInfo.PhoneNumber;

Problem is you could get null reference exception because any property in the chain could be null
(which you knew because you used all those null checks in your code).

 

Then what about this?

Try catch

string phone = null;
try { phone = building.Manager.ContactInfo.PhoneNumber; }
catch { }

No that’s is wrong. You should not use exception handling for controlling the flow.

More about this here

 

Null propagating operator

What if you could write like this?

var phone = building?.Manager?.ContactInfo?.PhoneNumber;

Unfortunately it is not available yet.
You can read more about the operator here.

 

Monad extension

What we want is something like the safe navigation operator where the code is clean.

var phone = building.=> Manager.=> ContactInfo.=> PhoneNumber;

That is not a valid syntax.


If we add some parentheses and some _ to make the syntax valid we could do this.

var phone = building._(_=>_.Manager)._(_=>_.ContactInfo)._(_=>_.PhoneNumber);


This looks a little cryptic I admit but the intend should be clear.
You want to safely extract the PhoneNumber without getting null reference exception.

This syntax is possible if you use this extension method.

MonadExtension.cs

public static class MonadExtension
    {
        public static TTo _<TFrom, TTo>(this TFrom input, Func<TFrom, TTo> evaluator) 
             where TFrom : class
        {
            return input == null ? default(TTo) : evaluator(input);
        }    
    }

This is an example of a Maybe Monad.

You can read more about Monads here.

 

Cleaner syntax

The syntax is not very clean and is usually to cryptic for must people in the example above.
The Monad extension in C# are usually preferred in this style.

var phone = building
            .With( b => b.Manager)
            .With( m => m.ContactInfo)
            .With( c => c.PhoneNumber);

If you want to return a default value in case there is a null somewhere in the property chain.
Then the return extension method is used.

var phone = building
            .With( b => b.Manager)
            .With( m => m.ContactInfo)
            .Return( c => c.PhoneNumber, "unknown");

MonadExtension.cs

public static class MonadExtension
    {
        public static TTo With<TFrom, TTo>(this TFrom input, Func<TFrom, TTo> evaluator) 
             where TFrom : class
        {
            return input == null ? default(TTo) : evaluator(input);
        }    

        public static TTo Return<TFrom, TTo>(
             this TFrom input, Func<TFrom, TTo> evaluator, TTo failureValue) 
             where TFrom : class
        {
            return input == null ? failureValue : evaluator(input);
        }
    }

This is an example of a Monads implementation for C#. I encourage you to read this channel9 post. This might inspire you to write ‘more clean code’.


EDIT:
There is also this alternative found at http://stackoverflow.com/a/4281533/815507

var phone = building.GetValueOrDefault(b => b.Manager.ContactInfo.PhoneNumber);
Advertisements

Written by kunuk Nykjaer

June 4, 2014 at 10:38 am

Posted in Csharp

Tagged with ,

One Response

Subscribe to comments with RSS.

  1. Reblogged this on Dinesh Ram Kali..

    dineshramitc

    June 14, 2014 at 7:10 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: