Also available at

Also available at my website http://tosh.me/ and on Twitter @toshafanasiev

Friday, 29 June 2012

An Ode to Ruby in C#

I love going off and exploring new languages, particularly when it allows (forces) me to think differently about the kind of stuff I generally take for granted. Take Ruby for instance. In Ruby you can do this

10.times do |i|
  puts "The square of #{i} is #{i * i}"
end
Which outputs
The square of 0 is 0
The square of 1 is 1
The square of 2 is 4
The square of 3 is 9
The square of 4 is 16
The square of 5 is 25
The square of 6 is 36
The square of 7 is 49
The square of 8 is 64
The square of 9 is 81

This is cool - the iteration construct reads like a sentence (perhaps not uttered in the speaker's first language, but a sentence all the same). The do ... end bit is called a block and it's a bit of code you can pass to a function to be executed at that function's discretion; the i between the pipe symbols is the parameter list for the block and the funky #{ ... } construct allows string interpolation - the evaluation of expressions inside a string literal.

Now I'm not going to get carried away here - the string interpolation can probably wait for a later post - but I can see value in being able to pass a lump of code, in a very readable way, to another function. The trite example above doesn't really do justice to the power this construct offers; features such as logging, timing, thread synchronisation, iteration, error protection, deterministic cleanup, inversion of control etc. are all candidates for this sort of code injection - with heavy emphasis on readability.

Now, I say to myself, modern C# supports lambdas and extension methods mean that you can simulate Ruby's ability to re-open and add to a class definition, I can do that; and this is what I come up with

    public static class Extensions
    {
        public static void Times(this int number, Action<int> action)
        {
            for (var i = 0; i < number; ++i)
                action(i);
        }
    }

Which is used like this

    10.Times(
        i => Console.WriteLine("The square of {0} is {1}", i, i * i)
    );

That's not bad, I think, it's pretty terse, but I can almost hear my Ruby friends tut as they catch sight of the lone punctuation on the last line. I can do better, but I'll need a new class.

    public sealed class Block<T>
    {
        private readonly Action<Action<T>> wrapper;
        public Block(Action<Action<T>> wrapper)
        {
            if (wrapper == null)
                throw new ArgumentNullException("wrapper");

            this.wrapper = wrapper;
        }
        public Action<T> Do { set { wrapper(value); } }
    }

    public static class Extensions
    {
        public static Block<int> Times(this int number)
        {
            return new Block<int>(action =>
            {
                for (var i = 0; i < number; ++i) action(i);
            });
        }
    }

Having set this up I can now call it like this

    10.Times().Do = i =>
        Console.WriteLine("The square of {0} is {1}", i, i * i);

I like this. Assigning the lambda to the write-only property has the effect of passing it to whatever wrapper the Block was initialised with. The Block class is a reusable little nugget of orchestration that's totally decoupled from whatever logic you choose to use it with, but the best part is it's quite declarative at the call site; and if you squint a bit you don't even see the assignment and lambda operators :)

Ok, but this seems pretty much geared to enumeration/iteration, what about a more generalised code injection scenario?

    public sealed class Block
    {
        private readonly Action wrapper;
        public Block(Action wrapper)
        {
            if (wrapper == null)
                throw new ArgumentNullException("wrapper");

            this.wrapper = wrapper;
        }
        public Action Do { set { wrapper(value); } }
    }

    public static class Wrap
    {
        public static Block With(Action wrapper)
        {
            return new Block(wrapper);
        }
    }

It's the same class! Well, nearly - it's the Block equivalent to Action<T>'s non-generic counterpart (I'd love to find a way to coalesce the two). The Wrap class here doesn't really add anything other than making the call site a bit more sentencey, as shown below

        var withLogging = Wrap.With(action =>
            {
                Console.Write("1. Before\n2. During: ");
                try
                {
                    action();
                    Console.WriteLine("3. After");
                }
                catch (Exception ex)
                {
                    Console.WriteLine("3. Exception: {0}", ex.Message);
                }
                finally
                {
                    Console.WriteLine("4. Cleanup");
                }
            });

With that variable in scope I can do this

        withLogging.Do = () => Console.WriteLine("This is going ok.");

        Console.WriteLine();

        withLogging.Do = () =>
        {
            Console.WriteLine("This might not go so well...");
            throw new Exception("KERBLAM!");
        };

With the following output

1. Before
2. During: This is going ok.
3. After
4. Cleanup

1. Before
2. During: This might not go so well...
3. Exception: KERBLAM!
4. Cleanup

All in all I'm pretty pleased with this. The idea could also be extended to functions returning values by means of the Func<T> family of delegates.

Afterthought: is this an instantiation of a named pattern?

No comments:

Post a Comment