Ruby-style keyword hashes in C# 3.0 January 7, 2008
Posted by James Webster in : development , trackbackI have been taking a look at some of C# 3.0’s new features now that Visual Studio 2008 and .Net 3.5 are now RTM, and have been wondering what patterns might emerge from them. I wonder if the automatic property and object initializer features might permit a similar pattern to Ruby’s ‘hash arguments’ functionality that is frequently used to simulate optional keyword arguments.
Consider the example Ruby on Rails ActiveRecord code below, taken from the RoR documentation for ActiveRecord. It demonstrates how multiple, optional arguments can be passed to a method and those arguments can be specified via a keyword (actually a key into a hashtable/dictionary).
Person.find(:first)
Person.find(:first,
:conditions => [ "user_name = ?", user_name])
Person.find(:first,
:order => "created_on DESC",
:offset => 5)
Obviously there is a set of keyword arguments that ActiveRecord will look for, and anything else will be ignored. The typing with respect to the hash is strong yet dynamic.
In the C# 3.0 world we would implement a class that statically declares the permitted ‘keyword arguments’…
public class FindOptions {
private bool all = true;
private string lock = "NO LOCK";
public bool All {
get { return all; }
set { all = value; }
}
public bool First { get; set; }
public string GroupBy { get; set; }
public int Limit { get; set; }
public string Lock {
get { return lock; }
set { lock = value; }
}
}
Automatic properties let us short-cut the definition of properties for which the default value (0, false, null, etc) is acceptable. Where we prefer to have an alternative default it will be necessary to fully-specify the property as in the case of the All and Lock properties in the above example. Ilya Ryzhenkov, Resharper Product Manager at Jetbrains, wonders if the inability to set a default value for an automatic property means that this feature is incomplete and I would tend to agree.
Our equivalent to the ActiveRecord-generated Person class in the Ruby example above would be a DAO, which would accept an instance of our FindOptions class as a parameter…
public class PersonFinder {
// Option #1 - using specified FindOptions
public Person[] BySurname(string surname,
FindOptions options) {
// ...code to find and return a Person...
}
// Option #2 - using default FindOptions
public Person[] BySurname(string surname) {
return BySurname(surname, new FindOptions());
}
}
We would then use both classes in combination as follows, taking advantage of the property initialization syntax in C# 3.0 …
PersonFinder people = new PersonFinder();
people.BySurname("Webster",
new FindOptions {First = true});
people.BySurname("Smith",
new FindOptions {Limit = 100, GroupBy = "FirstName" });
people.BySurname("Jones");
This style is definitely not idiomatic C# but I am wondering if it will become a useful idiom within the scope of C# 3.0. All this could be simplified further if C# supported a concise Dictionary initialization syntax!
Also worth keeping an eye on, Mono.Rocks, a growing utility library consisting of extension methods to bring fluent interfaces to CLR classes (more over at InfoQ).
Comments»
While Microsoft themselves are using anonymous types as dictionaries in their new MVC framework, I can’t imagine not solving this specific problem in LINQ, if you’re worried about idioms.