Over the past three days I’ve been bringing my C# skills up to date by reading C# in Depth, which I’ve found to be a good description of both how to use and the reasoning and mechanisms behind the new features of C# versions 2 and 3. Whilst I had reasonable experience of C#2 and a passing knowledge of C#3, after reading the book I feel more confident in using the features.
I wondered how the new features would fit into my language world view. I was pleasantly surprised at how familiar most of the concepts were, mainly thanks to my recent work with Python and Ruby. Many of the enhancements fill in the gaps in what I remembered of C#.
While many of the changes in C#3 were focused on enabling LINQ, even of themselves the result is a language which is just plain more pleasurable to work with. So here are a few features I found particularly pleasing.
Finally, decent type inference makes it into a mainstream language. Having to type
Dictionary<String, int> d = new Dictionary<String, int> is no more, instead we just state the type once:
var d = new Dictionary<String, int> and let the compiler spot the obvious.
More than this, the inference in the C#3 compiler isn’t as dumb as in C#2. It now uses those clever iterative inference methods I remember from my compiler courses at university. This makes my fingers and brain happy. Less typing and I see some use of those clever methods outside academia.
Whilst I feel calling these lambda methods is rather aggrandising them, the delegate and expression tree creating shorthand is welcome, especially when considered alongside the type inference capabilities of the C#3 compiler. Both Python and Ruby use their equivalent of delegate passing extensively. I find this way of working intuitive and clear, so I’m pleased to see it making inroads into more “traditional” languages. Lambda expressions make this more readable in C# code.
On the subject of shorthands, it’s a shame more haven’t made it into C#. The language could possibly learn from Scala’s example in making more natural DSLs possible with a little syntax help. Still, Lambda methods and extension methods go some way toward making writing fluent code simpler.
As parallel processing becomes more widely used, the practice of passing delegates to task execution libraries only increase. Lambda delegate declaration will make code using these libraries much simpler. I’ll be keeping a close eye on the Parallel Extensions work in C#4. Hopefully the Parallel Tasks portion of this will be as useful and simple to use as the Task Executor classes in Java, which I’m impressed by. Reading through the LINQ sections of C# in Depth, I was almost crying with the obvious parallelism which could be provided, so I was very pleased to discover the PLINQ work.
Again, experience with closure in many other languages helps with grasping the concepts used here (also present in anonymous delegates in C#2, but the usage of delegates seems on the increase in C#3). Frankly, I wouldn’t look forward to working in a language where this type of feature—anonymous methods with closure—isn’t available.
Again, a shorthand, but one which I’d become used to in dynamic languages, is the syntax support for lists and dictionaries. So it is in C#3, to an extent, and we can combine this with a new object initialisation syntax to make much more readable code.
We can go from the convoluted
to the much clearer
To me, this is a significant readability improvement when working with collections, which in my experience is more common than arrays where a similar syntax was possible. You get used to this when working with Python and Ruby, which seem to express intent much more clearly than Java or C#, where I often find mechanics get in the way.
Many of the changes between C# 1 and 3 support making intent clearer and mechanics less so. From C# in Depth, most of the backend does what you’d expect, moving boiler plate code to where it should be—implemented once in the framework with care, rather than haphazardly throughout codebases.
Many of these features are all about reducing needless clutter in code and putting work into the compiler—-and surprisingly, none of the new C#3 features require changes to the CLR itself. This is important: there’s no dynamic or duck-typing going on here, even though the lack of visible types sometimes gives that impression. The compiler must be able to infer the type and the CLR is still statically typed at it’s core. Once you understand this, I find understanding the way new features work much easier.
Next I plan to look at the ASP.NET MVC framework, to see how it compares with the web frameworks I’ve been working with most recently, Rails and Pylons, both heavily MVC-based. I wonder if ASP.NET MVC will provide what Rails promises: “Web development that doesn’t hurt”.