Sunday, January 6, 2008

Misunderestimating C# 3.0

Dare Obasanjo, who's posts on C-Omega I've enjoyed very much in the past, has written a new article called Does C# 3.0 Beat Dynamic Languages at their Own Game? He does a good job of pointing out the way that C# 3.0 adds features commonly associated with Dynamic Languages (tuples, adding methods to existing classes) without abandoning static typing.

Unfortunately he misses the mark with his criticism of type inference. Take a look at his code sample:



Look at the portion highlighted in red. Dare laments that he cannot write new {Weight = voteFunc(item), Item=item, FeedTitle = feedTitle } and must instead create a Vote class. The reason for this is that he is adding votes to a List and to instantiate this list he must parameterize the generic List with the Vote type.

Now let's rewrite that code snippet using the idioms of C# 3.0:



I wrote the ToProjectedDictionaryOfLists function. It is an extension method on IEnumerable<T> and it accepts two lambda functions. One that accepts an item in the stream and returns a key for the dictionary and another that accepts an item in the stream and converts it into a different representation ("projects" it). Using these functions, a key and value is derived for each item in the stream. This information is used to populate the dictionary with lists of items that share the same key value.

It's important to notice four things about our replacement code:

1. We've specified no type information (type inference in full effect)
2. We've liberated the code that moves the data into a hash table from the code that creates the code.
3. We've abstracted the action of creating a dictionary of lists from a stream of data into a reusable function.
4. We've expressed the problem in such a way that it can be trivially parallelized.

In previous blog posts I mused that Linq's superficial similarity to SQL might keep developers from realizing how widely applicable it is. Dare mentions Linq in the article but fails to recognize that he could use it to improve his example code in every measure.

This is really about functional programming vs. imperative programming. Because of its inherent advantages developers should always try and solve a problem functionally first and fall back to imperative solutions only where the result is more readable. In C# a functional solution was rarely more readable because the language lacked the idioms to support it. C# 3.0 makes huge strides in this area. This should have a profound effect on the way you code. If your C# 3.0 code looks like your C# 2.0 with "var" statements and the occasional Linq query against a database you've got to some remedial reading to do. :-) Trust me, you'll be glad you did.

Here is the code for the ToProjectedDictionaryOfLists function:




About Me

My photo
I'm a software developer who started programming at age 16 and never saw any reason to stop. I'm working on the Presentation Platform Controls team at Microsoft. My primary interests are functional programming, and Rich Internet Applications.