Evil use of Maybe monad and extension methods in C#?

Judah Gabriel Himango picture Judah Gabriel Himango · Jul 28, 2009 · Viewed 11.2k times · Source

edit 2015 This question and its answers are no longer relevant. It was asked before the advent of C# 6, which has the null propagating opertor (?.), which obviates the hacky-workarounds discussed in this question and subsequent answers. As of 2015, in C# you should now use Form.ActiveForm?.ActiveControl?.Name.


I've been thinking about the null propagation problem in .NET, which often leads to ugly, repeated code like this:

Attempt #1 usual code:

string activeControlName = null;
var activeForm = Form.ActiveForm;
if (activeForm != null)
{
    var activeControl = activeForm.ActiveControl;
    if(activeControl != null)
    {
        activeControlname = activeControl.Name;
    }
}

There have been a few discussions on StackOverflow about a Maybe<T> monad, or using some kind of "if not null" extension method:

Attempt #2, extension method:

// Usage:
var activeControlName = Form.ActiveForm
                          .IfNotNull(form => form.ActiveControl)
                          .IfNotNull(control => control.Name);

// Definition:
public static TReturn IfNotNull<TReturn, T>(T instance, Func<T, TReturn> getter)
    where T : class
{
    if (instance != null ) return getter(instance);
    return null;
}

I think this is better, however, there's a bit of syntactic messy-ness with the repeated "IfNotNull" and the lambdas. I'm now considering this design:

Attempt #3, Maybe<T> with extension method

// Usage:
var activeControlName = (from window in Form.ActiveForm.Maybe()
                         from control in window.ActiveControl.Maybe()
                         select control.Name).FirstOrDefault();

// Definition:
public struct Maybe<T> : IEnumerable<T>
      where T : class
{
    private readonly T instance;

    public Maybe(T instance)
    {
        this.instance = instance;
    }

    public T Value
    {
        get { return instance; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return Enumerable.Repeat(instance, instance == null ? 0 : 1).GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

public static class MaybeExtensions
{
    public static Maybe<T> Maybe<T>(this T instance)
        where T : class
    {
        return new Maybe<T>(instance);
    }
}

My question is: is this an evil abuse of extension methods? Is it better than the old usual null checks?

Answer

Daniel Earwicker picture Daniel Earwicker · Jul 28, 2009

It's interesting that so many people independently pick the name IfNotNull, for this in C# - it must be the most sensible name possible! :)

Earliest one I've found on SO: Possible pitfalls of using this (extension method based) shorthand

My one (in ignorance of the above): Pipe forwards in C#

Another more recent example: How to check for nulls in a deep lambda expression?

There are a couple of reasons why the IfNotNull extension method may be unpopular.

  1. Some people are adamant that an extension method should throw an exception if its this parameter is null. I disagree if the method name makes it clear.

  2. Extensions that apply too broadly will tend to clutter up the auto-completion menu. This can be avoided by proper use of namespaces so they don't annoy people who don't want them, however.

I've played around with the IEnumerable approach also, just as an experiment to see how many things I could twist to fit the Linq keywords, but I think the end result is less readable than either the IfNotNull chaining or the raw imperative code.

I've ended up with a simple self-contained Maybe class with one static method (not an extension method) and that works very nicely for me. But then, I work with a small team, and my next most senior colleague is interested in functional programming and lambdas and so on, so he isn't put off by it.