Showing posts with label functional. Show all posts
Showing posts with label functional. Show all posts

Thursday, 28 January 2010

Tuple.Do

Another example of using extension methods to improve the readability of your code.


Version 4 of the .NET Framework introduces a new Tuple type; or rather, a set of Tuple types with different numbers of generic parameters. Tuples represent an ordered set of values, and are first-class features in some languages, particularly functional ones such as F#, which can return multiple values from a function, as in this example (which requires the PowerPack DLL):

let success, value = TryParseInt("42")

This is considerably more elegant than using an "out" parameter, which requires explicit variable declarations prior to the call.

In .NET 4.0, the BCL Tuple type is compatible with F#'s native Tuples, but can also be used from C# (and other CLI languages). C# lacks the syntactic sugar of F#, so the call above would return an instance of Tuple<bool, int> in which the "success" value was referred to by the Item1 property, and the value by the Item2 property.

For example:

var tuple = TryParseInt("42");
if (tuple.Item1)
{
  Console.WriteLine("Success: {0}", tuple.Item2);
}
else
{
  Console.WriteLine("Fail");
}


To me, this is less than ideal, and in thinking about it I was reminded of a common pattern from Ruby, where functions often take a "block" (Ruby's version of an Action or Func) and call it with the value(s) that would be returned from the method.

It's simple to reproduce this feature in C#, using an extension method on the Tuple<T1,T2> type:

using System;

namespace System.Linq
{
  public static class TupleDoExtensions
  {
    public static void Do<T1, T2>(this Tuple<T1, T2> tuple,
Action<T1, T2> action)
    {
      action(tuple.Item1, tuple.Item2);
    }
  }
}

With this extension method, we can specify meaningful names for the return values as the parameters to an anonymous method, thus:

TryParseInt("42").Do((success, value) =>
{
  if (success)
  {
    Console.WriteLine("Success: {0}", value);
  }
  else
  {
    Console.WriteLine("Fail");
  }
}

I think this code is a lot more readable. Another victory for extension methods.

Followers