Inside F#

Brian's thoughts on F# and .NET

Transactional effects, part one

Posted by Brian on April 10, 2009

This blog entry describes a useful idiom for coding a set of effects that need ‘commit-or-rollback’ semantics.

Overview

Often times when you’re writing code, you have objects that need to maintain some invariants among two or more pieces of mutable state.  When you do an operation with a side-effect, you may need to update more than one piece of state in a way that preserves the invariant.  Since some sub-operations may fail (e.g. with exceptions), you have to be careful to ensure the invariants are preserved even if the face of a failure mid-stream.  Often times this means ‘undo’ing some effects to return to the original state.  The stuff I am talking about is a lot like transactions, e.g. ‘atomic’ and ‘consistent’, with ‘commit-or-rollback’ semantics.

When the ‘effects’ are just changing values of variables, it is easy to ‘undo’ these effects – just change the variable back to its original value.  But sometimes effects cannot be un-done.  If I paint the walls of my bedroom blue, and then I decide I don’t like the color, I can’t simply click ‘undo’ to get back to the previous state of the world.  (It sure would be handy if I could!)  However I can do a ‘compensating action’ to bring me back to the original state – namely, I can paint the walls again, back to the original color.

Similar kinds of ‘non-undo-able’ effects happen in software.  If I call Dispose() on an IDisposable, this cannot be undone.  (But I might be able to create a new object in the same state as the one I just Dispose()d.)  If I delete or rename a file on the file system, I may not be able to simply ‘undo’ these actions (but one can imagine possible ‘compensating actions’ to return the filesystem to its original state).  To sum up, there are times when you may find you need to ‘effectively-undo’ certain actions by performing other ‘compensating’ actions.  But it can be non-trivial to write code that does this correctly.

Example

Let’s consider a contrived and silly example to make this more concrete.  Suppose I get a new job offer I want to take.  I need to quit my old job, move into my new office and paint the office walls my favorite color, and fill out all the usual new-job paperwork.  The catch is, some of these operations may fail and revoke the job offer.  So if I quit my old job before I actually get the new job finalized, I need to go beg for my old job back as a ‘compensating action’.  And if I paint the walls of my new office before the new job paperwork is committed, I may have to paint the walls back to the original color as compensating action.

To model this in a simple program, I will just print out the commentary of what is happening.  Here’s some sample C# methods that implement the actions and compensations I described:

    static Random rng = new System.Random(0);

    static void QuitMyOldJob()
    { Console.WriteLine("I quit!"); }

    static void GetMyOldJobBack()
    { Console.WriteLine("<get down on knees and beg for old job back>"); }

    static void MoveIntoNewOffice()
    {
        Console.WriteLine("I will paint my new office :)");
        if (rng.Next(2) == 0)
        {
            Console.WriteLine("They don’t let you paint the walls!  They took away the job offer!");
            throw new Exception("BUMMER!");
        }
        Console.WriteLine("<painted the office blue>");
    }

    static void UndoMoveIntoNewOffice()
    { Console.WriteLine("<painted the office back to white>"); }

    static void GetPaperworkApproved()
    {
        if (rng.Next(2) == 0)
        {
            Console.WriteLine("They discovered you are an ex-con and took away the job offer!");
            throw new Exception("BOOO!");
        }
        Console.WriteLine("Your paperwork is ok!");
    }

Now the goal is to glue these bits together into a program with one of these three possible outputs…

    /*
    I got a new job offer!  Here is my story…
    I quit!
    I will paint my new office :)
    <painted the office blue>
    Your paperwork is ok!
    Success!

    I got a new job offer!  Here is my story…
    I quit!
    I will paint my new office :)
    They don’t let you paint the walls!  They took away the job offer!
    <get down on knees and beg for old job back>
    Oh no, the whole thing fell apart at the last minute: BUMMER!

    I got a new job offer!  Here is my story…
    I quit!
    I will paint my new office :)
    <painted the office blue>
    They discovered you are an ex-con and took away the job offer!
    <painted the office back to white>
    <get down on knees and beg for old job back>
    Oh no, the whole thing fell apart at the last minute: BOOO!
     */

…depending on whether certain phases fail. In the first case, everything succeeds, in the second case, trying to paint the walls fails, and in the third case, the failure happens when completing the job paperwork.  So how would you implement it in C#?

Here is one possible way:

        Console.WriteLine("I got a new job offer!  Here is my story…");
        try
        {
            QuitMyOldJob();
            try
            {
                MoveIntoNewOffice();
            }
            catch (Exception)
            {
                GetMyOldJobBack();
                throw;
            }
            try
            {
                GetPaperworkApproved();
            }
            catch (Exception)
            {
                UndoMoveIntoNewOffice();
                GetMyOldJobBack();
                throw;
            }
            Console.WriteLine("Success!");
        }
        catch (Exception e)
        {
            Console.WriteLine("Oh no, the whole thing fell apart at the last minute: {0}", e.Message);
        }

This is straightforward – for each action that can possibly fail, we surround it with a try-catch and in the catch block we do any necessary compensating actions before re-throwing the exception.  This works, but the code is a bit of a mess; when you face a similar situation with real code (rather than all these one-liner function calls) it can become very hard to reason about all the paths through the code to ensure everything works correctly.

A better abstraction

What we need is a handy way to group actions with their compensations and the failure semantics.  It turns out that with a suitable method which I’ll call "Transactional.Do", we can rewrite the code like this:

        Console.WriteLine("I got a new job offer!  Here is my story…");
        try
        {
            Transactional.Do(QuitMyOldJob, GetMyOldJobBack, () =>
                Transactional.Do(MoveIntoNewOffice, UndoMoveIntoNewOffice, () =>
                    GetPaperworkApproved()));
            Console.WriteLine("Success!");
        }
        catch (Exception e)
        {
            Console.WriteLine("Oh no, the whole thing fell apart at the last minute: {0}", e.Message);
        }

What a difference!  21 lines of code in the original example were reduced to 4 lines of code here.  Let’s take a closer look at this; here’s the definition of the "Transactional" class:

class Transactional
{
    /// Run ‘stepWithEffect’ followed by continuation ‘k’, but if the continuation later fails with
    /// an exception, undo the original effect by running ‘compensatingEffect’.
    /// Note: if ‘compensatingEffect’ throws, it masks the original exception.
    public static B Do<A, B>(Func<A> stepWithEffect, Action<A> compensatingEffect, Func<A, B> k)
    {
        var stepCompleted = false;
        var allOk = false;
        A a = default(A);
        try
        {
            a = stepWithEffect();
            stepCompleted = true;
            var r = k(a);
            allOk = true;
            return r;
        }
        finally
        {
            if (!allOk && stepCompleted)
            {
                compensatingEffect(a);
            }
        }
    }
    // if A == void, this is the overload
    public static B Do<B>(Action stepWithEffect, Action compensatingEffect, Func<B> k)
    {
        return Do(
            () => { stepWithEffect(); return 0; },
            (int dummy) => { compensatingEffect(); },
            (int dummy) => { return k(); });
    }
    // if A & B are both void, this is the overload
    public static void Do(Action stepWithEffect, Action compensatingEffect, Action k)
    {
        Do(
            () => { stepWithEffect(); return 0; },
            (int dummy) => { compensatingEffect(); },
            (int dummy) => { k(); return 0; });
    }
}

Check out the body of the main ‘Do’ method; it encompasses the general logic of what we need.  Namely, if after completing some action, later actions fail, then we need to ‘undo’ the original effect by running a compensation.  If everything succeeds, or if things fail before we have even done the original effect, then there is nothing to undo; in the former case, we ‘commit’ the result, whereas in the latter case nothing happened yet.  (The last two overloads just deal with the annoyance that ‘void’ is special in C# and you need overloads to deal with both Action<Arg> (when there is no return value) and Func<Arg,Result> (when there is); practically every C# API that uses Action/Func needs to have multiple overloads like this.)

With this handy little class, it becomes easy to write short, correct, readable code with transactional effects.

Commentary, and looking forward

This strategy has some limitations in C#, but is nonetheless an effective way to deal with cases where you have a number of sequential effects that need transactional semantics (either everything successfully commits, or else everything ‘rolls back’ to the original state) where each effect has its own ‘undo’ compensation.  I am interested to hear comments/feedback on the approach, as I don’t recall seeing it before, but in retrospect it seems to me like an obviously useful thing.

It also happens that Transactional.Do has the right signature to be the ‘Bind’ of a monad, and so in a future blog entry I’ll show how to capture this abstraction in F# using computation expressions, and hopefully show how the F# syntax sugars overcome some of the limitations you’d have in C# (I say ‘hopefully’ because I haven’t worked out all the details fully yet myself).

About these ads

One Response to “Transactional effects, part one”

  1. adam said

    Nice blog, I like seeing the functional coding style brought to c#, can\’t wait for the F# sugar.

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

 
Follow

Get every new post delivered to your Inbox.

Join 30 other followers

%d bloggers like this: