views:

3531

answers:

12

I have over the course of a few projects developed a pattern for creating immutable (readonly) objects and immutable object graphs. Immutable objects carry the benefit of being 100% thread safe and can therefore be reused across threads. In my work I very often use this pattern in Web applications for configuration settings and other objects that I load and cache in memory. Cached objects should always be immutable as you want to guarantee they are not unexpectedly changed.

Now, you can of course easily design immutable objects as in the following example:

public class SampleElement
{
  private Guid id;
  private string name;

  public SampleElement(Guid id, string name)
  {
    this.id = id;
    this.name = name;
  }

  public Guid Id
  {
    get { return id; }
  }

  public string Name
  {
    get { return name; }
  }
}

This is fine for simple classes - but for more complex classes I do not fancy the concept of passing all values through a constructor. Having setters on the properties is more desirable and your code constructing a new object gets easier to read.

So how do you create immutable objects with setters?

Well, in my pattern objects start out as being fully mutable until you freeze them with a single method call. Once an object is frozen it will stay immutable forever - it cannot be turned into a mutable object again. If you need a mutable version of the object, you simply clone it.

Ok, now on to some code. I have in the following code snippets tried to boil the pattern down to its simplest form. The IElement is the base interface that all immutable objects must ultimately implement.

public interface IElement : ICloneable
{
  bool IsReadOnly { get; }
  void MakeReadOnly();
}

The Element class is the default implementation of the IElement interface:

public abstract class Element : IElement
{
  private bool immutable;

  public bool IsReadOnly
  {
    get { return immutable; }
  }

  public virtual void MakeReadOnly()
  {
    immutable = true;
  }

  protected virtual void FailIfImmutable()
  {
    if (immutable) throw new ImmutableElementException(this);
  }

  ...
}

Let's refactor the SampleElement class above to implement the immutable object pattern:

public class SampleElement : Element
{
  private Guid id;
  private string name;

  public SampleElement() {}

  public Guid Id
  {
    get 
    { 
      return id; 
    }
    set
    {
      FailIfImmutable();
      id = value;
    }
  }

  public string Name
  {
    get 
    { 
      return name; 
    }
    set
    {
      FailIfImmutable();
      name = value;
    }
  }
}

You can now change the Id property and the Name property as long as the object has not been marked as immutable by calling the MakeReadOnly() method. Once it is immutable, calling a setter will yield an ImmutableElementException.

Final note: The full pattern is more complex than the code snippets shown here. It also contains support for collections of immutable objects and complete object graphs of immutable object graphs. The full pattern enables you to turn an entire object graph immutable by calling the MakeReadOnly() method on the outermost object. Once you start creating larger object models using this pattern the risk of leaky objects increases. A leaky object is an object that fails to call the FailIfImmutable() method before making a change to the object. To test for leaks I have also developed a generic leak detector class for use in unit tests. It uses reflection to test if all properties and methods throw the ImmutableElementException in the immutable state. In other words TDD is used here.

I have grown to like this pattern a lot and find great benefits in it. So what I would like to know is if any of you are using similar patterns? If yes, do you know of any good resources that document it? I am essentially looking for potential improvements and for any standards that might already exist on this topic.

+3  A: 

You are still dealing with state, and thus can still be bitten if your objects are parallelized before being made immutable.

A more functional way might be to return a new instance of the object with each setter. Or create a mutable object and pass that in to the constructor.

Cory Foy
+3  A: 

System.String is a good example of a immutable class with setters and mutating methods, only that each mutating method returns a new instance.

dalle
I dodn't know it behaved like that, an interesting pattern!
Andrew Bullock
Just beware the double-edged sword; you can very quickly get a lot of gen0 objects for GC to worry about. Obviously this is particularly bad for string due to the size of each (hence StringBuilder), but it is still a consideration for a fluent mutating API.
Marc Gravell
+1  A: 

I dont like the idea of being able to change an object from a mutable to an immutable state, that kind of seems to defeat the point of design to me. When are you needing to do that? Only objects which represent VALUES should be mutable

Andrew Bullock
I basically use this pattern whenever I have a larger object model for configuration settings and the like. The object model can be serialized to XML and back to objects again using the XmlSerializer class which required setters on the objects.
Lars Fastrup
Can you clarify? objects that represent VALUES should absolutely be *im*mutable. Re making an object immutable, that is just the means-to-the-end. The end is an immutable class, which is highly desirable for multi-threaded / functional code.
Marc Gravell
My need for circular references and serialization basically calls for popsicle immutability as discussed two answers up.
Lars Fastrup
+5  A: 

After my initial discomfort about the fact that I had to create a new System.Drawing.Point on each modification, I've wholly embraced the concept some years ago. In fact, I now create every field as readonly by default and only change it to be mutable if there's a compelling reason – which there is surprisingly rarely.

I don't care very much about cross-threading issues, though (I rarely use code where this is relevant). I just find it much, much better because of the semantic expressiveness. Immutability is the very epitome of an interface which is hard to use incorrectly.

Konrad Rudolph
+9  A: 

Another option would be to create some kind of Builder class.

For an example, in Java (and C# and many other languages) String is immutable. If you want to do multiple operations to create a String you use a StringBuilder. This is mutable, and then once you're done you have it return to you the final String object. From then on it's immutable.

You could do something similar for your other classes. You have your immutable Element, and then an ElementBuilder. All the builder would do is store the options you set, then when you finalize it it constructs and returns the immutable Element.

It's a little more code, but I think it's cleaner than having setters on a class that's supposed to be immutable.

Herms
Yes, an element builder is a good idea. I did not go for this solution as my object models can also be transformed to Xml and back to objects again using the XmlSerializer class which requires setters on the objects.
Lars Fastrup
This approach, while valid, has a significant impact on the volume of code to maintain. Great for code-generator tools; not so great for humans.
Marc Gravell
+4  A: 

The (relatively) new Software Design paradigm called Domain Driven design, makes the distinction between entity objects and value objects.

Entity Objects are defined as anything that has to map to a key-driven object in a persistent data store, like an employee, or a client, or an invoice, etc... where changing the properties of the object implies that you need to save the change to a data store somewhere, and the existence of multiple instances of a class with the same "key" imnplies a need to synchronize them, or coordinate their persistence to the data store so that one instance' changes do not overwrite the others. Changing the properties of an entity object implies you are changing something about the object - not changing WHICH object you are referencing...

Value objects otoh, are objects that can be considered immutable, whose utility is defined strictly by their property values, and for which multiple instances, do not need to be coordinated in any way... like addresses, or telephone numbers, or the wheels on a car, or the letters in a document... these things are totally defined by their properties... an uppercase 'A' object in an text editor can be interchanged transparently with any other uppercase 'A' object throughout the document, you don't need a key to distinguish it from all the other 'A's In this sense it is immutable, because if you change it to a 'B' (just like changing the phone number string in a phone number object, you are not changing the data associated with some mutable entity, you are switching from one value to another... just as when you change the value of a string...

Charles Bretana
+11  A: 

For info, the second approach is called "popsicle immutability".

Eric Lippert has a series of blog entries on immutability starting here. I'm still getting to grips with the CTP (C# 4.0), but it looks interesting what optional / named parameters (to the .ctor) might do here (when mapped to readonly fields)... [update: I've blogged on this here]

For info, I probably wouldn't make those methods virtual - we probably don't want subclasses being able to make it non-freezable. If you want them to be able to add extra code, I'd suggest something like:

[public|protected] void Freeze()
{
    if(!frozen)
    {
        frozen = true;
        OnFrozen();
    }
}
protected virtual void OnFrozen() {} // subclass can add code here.

Also - AOP (such as PostSharp) might be a viable option for adding all those ThrowIfFrozen() checks.

(apologies if I have changed terminology / method names - SO doesn't keep the original post visible when composing replies)

Marc Gravell
Thanks - just the link I was looking for. Eric describes very precisely why this is useful when you are using circular references and serialization which I do.
Lars Fastrup
Thanks again - I totally agree the virtual methods are not an optimal design. I will refactor with your suggestions. I also like your frozen terminology :-)
Lars Fastrup
+2  A: 

Expanding on the point by @Cory Foy and @Charles Bretana where there is a difference between entities and values. Whereas value-objects should always be immutable, I really don't think that an object should be able to freeze themselves, or allow themselves to be frozen arbitrarily in the codebase. It has a really bad smell to it, and I worry that it could get hard to track down where exactly an object was frozen, and why it was frozen, and the fact that between calls to an object it could change state from thawed to frozen.

That isn't to say that sometimes you want to give a (mutable) entity to something and ensure it isn't going to be changed.

So, instead of freezing the object itself, another possibility is to copy the semantics of ReadOnlyCollection< T >

List<int> list = new List<int> { 1, 2, 3};
ReadOnlyCollection<int> readOnlyList = list.AsReadOnly();

Your object can take a part as mutable when it needs it, and then be immutable when you desire it to be.

Note that ReadOnlyCollection< T > also implements ICollection< T > which has an Add( T item) method in the interface. However there is also bool IsReadOnly { get; } defined in the interface so that consumers can check before calling a method that will throw an exception.

The difference is that you can't just set IsReadOnly to false. A collection either is or isn't read only, and that never changes for the lifetime of the collection.

It would be nice at time to have the const-correctness that C++ gives you at compile time, but that starts to have it's own set of problems and I'm glad C# doesn't go there.


ICloneable - I thought I'd just refer back to the following:

Do not implement ICloneable

Do not use ICloneable in public APIs

Brad Abrams - Design Guidelines, Managed code and the .NET Framework

Robert Paulson
I do not agree it has a bad smell to it. This form of immutability is known as "popsicle immutability" as pointed out by Marc and is very useful in certain scenarios. I just wish the compiler supported this type of immutable objects.
Lars Fastrup
I agree in principle with popsicle style, but the 'bad smell' is if it's used improperly. Sometimes objects are frozen, sometimes thawed. It can lead to rubbish client code if done incorrectly.
Robert Paulson
My suggestion to look at ReadOnlyCollection is because I prefer explicitness over a method call that can tell an object that it's no longer mutable. However I'm also talking in the more general case of immutability.
Robert Paulson
+1  A: 

Just a tip to simplify the element properties: Use automatic properties with private set and avoid explicitly declaring the data field. e.g.

public class SampleElement {
  public SampleElement(Guid id, string name) {
    Id = id;
    Name = name;
  }

  public Guid Id {
    get; private set;
  }

  public string Name {
    get; private set;
  }
}
spoulson
Thanks for the tip - another nifty little feature in C# 3.0 :-) I would for sure go with the private Setters if it was not because I need to be able to serialize/deserialize my object graphs using the XmlSerializer.
Lars Fastrup
Would be nice if the XmlSerializer were clever enough to correlate the constructor paramaters with the properties and construct the object using that constructor instead of the default constructor
Lars Fastrup
+1  A: 

Here is a new video on Channel 9 where Anders Hejlsberg from 36:30 in the interview starts talking about immutability in C#. He gives a very good use case for popsicle immutability and explains how this is something you are currently required to implement yourself. It was music to my ears hearing him say it is worth thinking about better support for creating immutable object graphs in future versions of C#

Expert to Expert: Anders Hejlsberg - The Future of C#

Lars Fastrup
+1  A: 

Two other options for your particular problem that haven't been discussed:

  1. Build your own deserializer, one that can call a private property setter. While the effort in building the deserializer at the beginning will be much more, it makes things cleaner. The compiler will keep you from even attempting to call the setters and the code in your classes will be easier to read.

  2. Put a constructor in each class that takes an XElement (or some other flavor of XML object model) and populates itself from it. Obviously as the number of classes increases, this quickly becomes less desirable as a solution.

Neil Whitaker