Sunday, January 06, 2008 7:37 PM bart

Exception Handling in functional style

What a joke you must think when reading this post's title. Isn't the functional paradigm all about side-effect free programming and the such? Well, it turns out you're absolutely right. So, why this post? I have to admit I had yet another crazy Sunday afternoon idea that I found worthwhile to open VS 2008 for and give it a short.

A long history short: I'm having a few mail threads currently on exception filtering in the CLR and the (lack of) language support for it (cf. Visual Basic's When keyword). Brave people would extend existing compilers to add support for such a feature, others (including me in Sunday afternoon moods) would rather put some library support together to achieve similar results (that being said, what you'll see next doesn't have the real CLR exception filter semantics, but with a bit (bunch?) of Reflection.Emit stuff one could achieve this, at runtime though).

Here's my take on how to write exception handlers in a functional style (as it turns out, the only reason to call it functional is a) it works, b) it uses lambdas and c) a couple of parentheses - exercise: find these two guys in the code below :-)).

class Program
{
    static void Main()
    {
        Action body = delegate {
            Console.WriteLine("Hello");
            throw new InvalidOperationException("Bang");
        };

        body.Catch<InvalidOperationException>(ex => ex.Message == "Oops", ex => Console.WriteLine("Oops!!!"))
            .Catch<InvalidOperationException>(ex => ex.Message == "Bang", ex => Console.WriteLine("Bang!!!"))
            .Catch<Exception>(ex => Console.WriteLine("Caught " + ex.Message + " using bad style..."))();
    }
}

It's not too hard to guess how it works: Catch<T> is an extension method on the Action class, having two overloads. The first two invocations you see, have some filtering logic (ex => ex.Message == "Oops" for example), the last one omits this. The reason for overloading on the left parameter is readability: you can read each line as "catch exception when filter using this code". However, if you come from the VB camp, overloading on the right would make more sense: "Catch exception using this code When filter".

The implementation of Catch isn't that difficult either:

static class Exceptions
{
    public static Action Catch<T>(this Action body, Action<T> handler) where T : Exception
    {
        return Catch<T>(body, ex => true, handler);
    }

    public static Action Catch<T>(this Action body, Func<T, bool> filter, Action<T> handler) where T : Exception
    {
        return delegate
        {
            try
            {
                body();
            }
            catch (T ex)
            {
                if (!filter(ex))
                    throw;
                else
                    handler(ex);
            }
        };
    }
}

And it's not too hard to imagine a Finally method too:

public static Action Finally(this Action body, Action @finally)
{
    return delegate
    {
        try
        {
            body();
        }
        finally
        {
            @finally();
        }
    };
}

Going even further, what about extending IDisposable with a Using method? The using keyword in C# basically emits a try ... finally ... statement with the finally block calling Dispose on the given object. So, it becomes:

public static Action Using(this IDisposable resource, Action block)
{
    return block.Finally(delegate {
        if (resource != null)
            resource.Dispose();
    });
}

Oh, and before you ask: you don't need to worry about using variables from the outer scope thanks to closures. There are more subtle things though, which I'll let the readers find out about as a New Year's gift :-) Happy exception handling in 2008!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under: ,

Comments

# re: Exception Handling in functional style

Monday, January 07, 2008 6:43 AM by Aaron

This seems like it would be difficult to debug. But this is interesting, what would it look like in VB?

# re: Exception Handling in functional style

Monday, January 07, 2008 6:17 PM by bart

Absolutely right Aaron; debugging is one of the subleties since you have all sorts of anonymous constructs and delegates around. That being said, stepping through is still doable (one recommendation: F9 the body.[...]() line, hit F5 and F11 through the code - quiz: predict the debugging order you'll observe), but hovering over lambda parameters doesn't reveal what's inside (although functions are just another piece of data, right?).

This being said, in the ideal world, a function does just (important word) what it's supposed to do (agreed, lame argument), so debugging inside the functional definition should be a no-no (consider it a black box), leaving the big one-liner something that just works (compare it to the case where you could - but you can't - jump into the inner workings of a foreach or using statement; it's just another abstraction).

As an additional debugging exploration: split the body.[...]() line into:

Action action = body.[...];

action();

and set a breakpoint on the last line. Step into it using F11. You might be a little surprised how good the yellow-line debugging experience is, even in the presence of lambdas...

-Bart

# A functional C# (type)switch

Thursday, April 10, 2008 9:17 PM by SZW

使用匿名函数扩展C#中的Switch

# A functional C# (type)switch

Thursday, April 10, 2008 9:17 PM by SZW

使用Lambda表达式扩展C#中的Switch

# Bart De Smet gone mad about Extension methods

Friday, April 25, 2008 5:53 AM by Techspace

Bart De Smet gone mad about Extension methods