Functional Inspiration – The With extension method

Adding a “With” extension method mimicking F#

This is the first entry of a blog series about how functional programming, and the F# training I recently went to, gives me inspiration in my day-to-day work in C#. The first one will show how you can build a “with”-like feature in C#.

One of the many features of F# that stroke me during Robert Pickering’s “Beginning F#” course, was the Record Type and its ease of use. For those of you that don’t know F#, a record type can be compared with a Tuple whose properties would be named.

For instance, this F# snippet defines a Record Type Person with two properties Name and Age.

type Person =
    { Name: string;
      Town: string;
      Country: string;
      Age: int }

With this type defined, it is now possible to define an instance of that type :

let someone =
    { Name = "Luc";
      Town = "Paris";
      Country = "France";
      Age = 29 }

A very handy feature of F# lets us now write this :

let someoneElse =
    { someone with
        Age = 30 }

The “with” keyword allow us to define “someoneElse” as a copy of “someone”, stating only the values of the properties to change.

In a project I have been working on recently, I had exactly the same need of defining a new instance with very little changes, but in C#. In order to do this, I wrote a simple extension method, base on the ICloneable interface :

public static class ClonableExtensions
{
    public static T With<T>(this T original,
                            Action<T> withAction)
        where T : ICloneable
    {
        T copy = (T)original.Clone();
        withAction(copy);
        return copy;
    }
}

With this extension method, if we define a class Person that implements the ICloneable interface, like this :

public class Person : ICloneable
{
    public string Name { get; set; }
    public string Town { get; set; }
    public string Country { get; set; }
    public int Age { get; set; }

    public object Clone()
    {
        return new Person()
        {
            Name = this.Name,
            Town = this.Town,
            Country = this.Country,
            Age = this.Age
        };
    }
}

It is now possible to use the generic With extension method to write the following code :

Person someone = new Person()
{
    Name = "Luc",
    Town = "Paris",
    Country = "France",
    Age = 29
};

Person someoneElse = someone.With(p => p.Age = 30);

I find this construct quite expressive and readable, but please note that there are several drawbacks :

  1. The C# objet has to be mutable. Its “Age” property is set after the object is created by the Clone method. Even though the Clone method could have used a copy constructor instead of setting properties, the generic With method must overwrite the properties values. Addendum : this problem is now solved in “Revisiting the With extension method”.
  2. The syntax to use in order to modify more than one property is less readable, because a lambda expression with multiple instructions has to be written between accolades.
  3. In the end, whatever you do, someoneElse will be 30, and his name is Luc.
This entry was posted in Functional Inspiration and tagged , . Bookmark the permalink.

Comments are closed.