Emulating F#'s 'with' Construct in C# using Parameter Object Design Pattern

This article introduces a way to emulate F#'s 'with' construct in C#. In particular, it is shown how a factory method can be implemented which creates a new object based on a provided template object and optional additional values (replacing values of the template object) in a type-safe way. While the presented solution doesn't use new C# 4.0 language features, using them for this task is also considered and discussed.

Introduction

Recently, I've had a look at the beautiful functional programming language F# [1], which runs on Microsoft.NET [2] as well as on Mono.NET [3]. For those of you who are not familiar with functional programming languages. These languages normally work with value objects. Once an object is created in memory it isn't mutable anymore. So in order to get a similar object where part of the object's state looks different one has to create a new object. F# provides a convenient construct to create new objects based on existing ones.

For instance, the following F# code creates a new type 'Attribute' with three fields 'StereoType', 'Name', and 'Value'. Then an object 'a1' of this type is created by specifying values for each field. Subsequently, an object 'a2' is created using 'a1' as template.

1
2
3
4
5
6
7
type Attribute = {StereoType : string;
                  Name : string;
                  Value : string;}
let a1 = {StereoType = "author-info";
          Name = "full-name";
          Value = "Johann Duscher";}
let a2 = {a1 with Value = "Jonny Dee";}

The above code yields the following F# interpreter response:

1
2
3
4
5
6
val a1 : Attribute = {StereoType = "author-info";
                      Name = "full-name";
                      Value = "Johann Duscher";}
val a2 : Attribute = {StereoType = "author-info";
                      Name = "full-name";
                      Value = "Jonny Dee";}

As you can see 'a2' has been created with the values of 'a1' except for the one specified within the 'with' construct. I think this is very convenient and I wished there were a similar construct in C# (how ever such a construct might possibly be realized) -- but there isn't. So I thought about a way to emulate this behaviour getting as much language support as possible. However, before I tell you my solution I came up with, I would like to show you my use case for which I needed it.

Let's assume there is a factory class which can create attribute instances like this:

1
2
3
4
5
6
7
8
9
10
11
public class DefaultFactory : IFactory
{
   public IAttribute CreateAttribute(string stereoType,
                                     string name,
                                     string value)
   {
      return new Attribute {StereoType = stereoType,
                            Name = name,
                            Value = value,};
   }
}

As you can infer from above code the 'Attribute' class implements the 'IAttribute' interface, which defines three properties 'StereoType', 'Name', and 'Value'. The factory method's parameters simply are passed to the corresponding setters of the 'Attribute's properties. This works well, but as soon as I want to create an attribute based on the values of another one things get chatty, because I need to provide all three values to the factory method.

1
2
3
4
5
6
var a1 = factory.CreateAttribute("author-info",
                                 "full-name",
                                 "Johann Duscher");
var a2 = factory.CreateAttribute(a1.StereoType,
                                 a1.Name,
                                 "Jonny Dee");

A first approach to improve the factory method could be to change it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public IAttribute CreateAttribute(IAttribute template,
                                  string stereoType,
                                  string name,
                                  string value)
{
   if (null != template)
   {
      if (null == stereoType)
         stereoType = template.StereoType;
      if (null == name)
         name = template.Name;
      if (null == value)
         value = template.Value;
   }
   return new Attribute {StereoType = stereoType,
                         Name = name,
                         Value = value,};
}

Then it would be possible to call this method as follows:

1
2
3
4
var a2 = factory.CreateAttribute(a1
                                 null,
                                 null,
                                 "Jonny Dee");

But there are some drawbacks. First of all, the 'null' value doesn't carry much information, so chances are big you provide a 'null' value to the wrong argument. Can you instantly tell which argument gets which value by just having a look at the method call? And now imagine a factory method with some more parameters. You could explicitly add a cast like '(string)null' to provide type information. But in the above case this wouldn't help either because all arguments are of type string.

Those of you who count to the lucky women or men who can already use C# 4.0 (beta) [4] in their projects might come up with the idea to to use optional, named parameters like this:

1
2
3
4
5
6
7
public IAttribute CreateAttribute(IAttribute template,
                                  string stereoType = null,
                                  string name = null,
                                  string value = null)
{
   ...
}

Indeed, this would allow to call the factory method in a way very close to F#'s way:

1
var a2 = factory.CreateAttribute(a1, value: "Jonny Dee");

That looks very nice, doesn't it? And for this example it does really work. You get a new attribute instance, which has equal values to 'a1', except for the 'Value' property, which gets the value provided in the method call. But this solution as well as the more error-prone previous one have another drawback. They don't work if you want to create an object which has a property value explicitly set to 'null'.

1
var a2 = factory.CreateAttribute(a1, value: null);

This code won't work as desired, because it would create a new attribute 'a2' qual to 'a1'. So in fact, the new nice features of C# 4.0 won't help us much. Too bad, isn't it? Honestly, I'm not as disappointed about that fact as it might seem. At work, I'm not (yet) able to use C# 4.0 features in my projects anyway. And at the time of this writing Mono project doesn't support these new features, either. There is work going on to make Mono's C# compiler compatible to 4.0 syntax, but it takes time... [5]

UPDATE (2009/12/11): I've just found an article telling that Mono C# compiler has now all features of C# 4.0. [9]

Solution

At this point, I would like to present my solution for this problem. It's based on the "Parameter Object" design pattern [6] and uses C#'s syntactic sugar for object initialization [7]. Code sometimes tells more than words:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class AttributeArgs : IAttribute
{
   public string StereoType { get; set; }
   public string Name { get; set; }
   public string Value { get; set; }
}
 
public class DefaultFactory : IFactory
{
   public IAttribute CreateAttribute(IAttribute template,
                                     AttributeArgs args)
   {
      if (null != template)
      {
         if (null == args.StereoType)
            args.StereoType = template.StereoType;
         if (null == args.Name)
            args.Name = template.Name;
         if (null == args.Value)
            args.Value = template.Value;
      }
      return new Attribute {StereoType = args.StereoType,
                            Name = args.Name,
                            Value = args.Value,};
   }
}

Yes I know, writing to the provided 'AttributeArgs' instance referenced by 'args' is not a good idea, because it might provoke unwanted side effects. But for sake of clarity... And on the other hand, sometimes the "Parameter Object" pattern is also used to provide a means for returning multipe result values [6]. Anyway, now it is possible to call the factory method as follows:

1
2
3
var a2 = factory.CreateAttribute(a1, new AttributeArgs {
                                        Value = "Jonny Dee",
                                     });

Not as nice as using C# 4.0 features, but nearly as nice and it works, no? You are right, this solution still has a problem with values which need to be set explicitly to 'null'. Again, providing 'null' as new value results in an attribute instance 'a2' equal to 'a1'. What is needed is a way to find out which values were explicitly provided. The following code will finally do the trick:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class AttributeArgs : IAttribute
{
   private string _stereoType;
   private string _name;
   private string _value;
 
   public string StereoType
   {
      get { return _stereoType; }
      set { _stereoType = value; StereoTypeSpecified = true; }
   }
 
   public bool StereoTypeSpecified { get; private set; }
 
   // The remaining properties are implemented analogously.
   ...
}
 
public class DefaultFactory : IFactory
{
   public IAttribute CreateAttribute(IAttribute template,
                                     AttributeArgs args)
   {
      if (null != template)
      {
         if (!args.StereoTypeSpecified)
            args.StereoType = template.StereoType;
         if (!args.NameSpecified)
            args.Name = template.Name;
         if (!args.ValueSpecified)
            args.Value = template.Value;
      }
      return new Attribute {StereoType = args.StereoType,
                            Name = args.Name,
                            Value = args.Value,};
   }
}

As you can see, for each property defined by the 'IAttribute' interface there is a corresponding property in the 'AttributeArgs' class. Furthermore, there is also a 'XxxSpecified' property which carries the information needed to figure out which properties were explicitly set within the parameter object instance. If you ever have had to cope with web service proxy classes generated by Visual Studio you might know this pattern [8].

Here is the F# example introduced at the beginning expressed in C#:

1
2
3
4
5
6
7
8
9
10
11
12
13
var a1 = factory.CreateAttribute(
            null,
            new AttributeArgs {
              StereoType = "author-info",
              Name = "full-name",
              Value = "Johann Duscher",
           });
 
var a2 = factory.CreateAttribute(
            a1,
            new AttributeArgs {
               Value = "Jonny Dee",
            });

You might already have noticed that the 'AttributeArgs' class implements 'IAttribute' interface, which is not necessary at all. But it helps to keep it in sync with the 'IAttribute' interface. As soon as you add a new property to it the compiler will complain that your parameter object class is missing an implementation for it. There is also another advantage. In some cases making the parameter object class implement the interface which is specified as the return type of the factory method can make the implementation class itself obsolete. This was the case in my project. So I was able to return an instance of 'AttributeArgs' itself as implementation.

1
2
3
4
5
6
7
8
public IAttribute CreateAttribute(IAttribute template,
                                  AttributeArgs args)
{
   ...
   return new AttributeArgs {StereoType = args.StereoType,
                             Name = args.Name,
                             Value = args.Value,};
}

The fact that the returned instance is actually an instance of class 'AttributeArgs' with additionally defined 'XxxSpecified' properties is totally transparent -- at least from the factory method caller's perspective.

Conclusion

Several approaches to emulate F#'s nice 'with' construct were discussed. It was shown that even C# 4.0 with it's pretty nice syntactic sugar for optional and named parameters doesn't help in many use cases. A final solution was presented which is solely based on the "Paremeter Object" design pattern and C#'s language feature for object initialization. The suggested solution introduces additional maintenance overhead. As a worst case, three entities need to be kept in sync. An interface, the corresponding implementation class, and a parameter object class. While it isn't necessary, it was suggested to make the parameter object class implement the interface, too, in order to get some compiler support. It was also shown that sometimes this can make a separate implementation class obsolete. In any case, when considering the general advantages you get with using the "Parameter Object" design pattern, and the convenience type-safe way you get for creating new objects based on template objects, while avoiding redundant code, the suggested solution might be worth the efforts.

References

1. MSDN: F# Developer Center
2. MSDN: .NET Framework Developer Center
3. Mono.NET
4. C# 4.0 on Wikipedia
5. Mono Project Roadmap
6. Parameter Object Design Pattern
7. MSDN: C# Object and Collection Initializers
8. MSDN: Omitting Values for Optional Web Service Objects
9. Marek Safar: Mono and C# 4.0