Wednesday, 5 November 2008

Immutability and optional parameters

(caveat: based on the October 2008 public VS2010 CTP; everything subject to change)

C# 3.0 made it very easy to initialize objects, in particular via "object initializer" syntax. This allows us to set the properties for an object (and child objects) very simply.

I'll give a simple example - but note that this makes a lot more sense where the class has lots of properties... obviously that isn't condusive to blogging, so you'll have to use your imagination ;-p

public sealed class Person {
public string Forename { get; set; }
public string Surname { get; set; }
// snip: other properties
static void Main() {
Person p = new Person {
Forename = "Fred",
Surname = "Flintstone"
};
}
}

In the Main method, we create and initialize the Person via the object initializer, setting the Forename and Surname properties.

OK; all good - but what about immutability? Unfortunately, it starts to break down.

public sealed class Person {
private readonly string forename, surname;
public string Forename { get {return forename; }}
public string Surname { get {return surname; }}
// snip: other properties

static void Main() {
Person p = new Person {
Forename = "Fred",
Surname = "Flintstone"
};
}
}

Error 1 Property or indexer 'Forename' cannot be assigned to -- it is read only
Error 2 Property or indexer 'Surname' cannot be assigned to -- it is read only

The problem is that object initializers work by invoking the setter, which can't happen if there *is* no setter.
Obviously we could add a constructor that sets both the forename and surname, but keep in mind that we might have 10 properties, and different callers might want to set different permutations of properties. We don't really want to add large numbers of constructors to support each caller's whim.

So what about C# 4.0? This introduces optional and named parameters... as well as making COM a lot more friendly, we can use this on our constructors to provide something close to an object initializer:

public sealed class Person {
// readonly fields/properties
private readonly string forename, surname;
public string Forename { get { return forename; } }
public string Surname { get { return surname; } }
// snip: other properties

// constructor with optional arguments
public Person(
string forename = "", string surname = ""
/* snip: other parameters */) {

this.forename = forename;
this.surname = surname;
// snip: other fields
}
static void Main() {
Person p = new Person(
forename: "Fred",
surname: "Flintstone");
}
}

Here, the Main method creates a new immutable Person, specifying just the properties that they want to assign. The rest are defaulted to whatever the "=foo" says in the constructor declaration.

Simple; easy.