A few weeks ago I finished reading C# in depth by Jon Skeet.
This is a magnificent book that details the changes to the C# language as the language evolved into C# 2 and 3. After a very brief history and review of some of the trickier concepts of C# (delegates and value types) it dives into the changes for C# 2 starting with a great explanation of generics and offering some observations that I haven’t come across before. It then moves on to an in-depth look at the co- and contra- variance of delegates and how variables are captured in anonymous methods, before covering the easier ways to write iterators using the yield statement. A final chapter on C# 2 briefly covers other changes such as partial classes, static classes, getter/setter property access separation and a couple of other changes.
After this it moves on to C# 3. Lambda expressions and expression trees are covered to a good level of detail, with an explanation of the changes to the type inference process of the compiler that were needed to allow a lot more implicit typing. (This is something I want to look at in a lot more detail). Extentsion methods are then introduced. After thisthe book moves on to query expressions and LINQ to objects, detailed coverage of the extension methods that turn IEnumerable streams into things that can be combined in very powerful ways. The final chapter covers LINQ to SQL and the way IQueryable can be used to allow Linq providers to convert expression trees into code that can be executed outside the world of C#. This is the mechanism used to convert a query written in C# into SQL that can be executed inside SQL server.
This book is truely great making loads of interesting observations along the way. I loved the way that it covers the plumbing of Linq in great detail before moving on to the query syntax that make query expressions very approachable in the C# language.
LINQ is great. It brings some of the ideas of lazy streams into a mainstream language. The idea of defining the effect of a Linq expression by defining the language to language transform needed for compiling it reminded me very much of the way macros in Lisp can be used to define advanced language concepts in terms of more basic concepts. There’s a good paper by Henry Baker, Metacircular semantics of Common Lisp special forms, that does this for the language of Common Lisp, explaining how many of the control constructs of the language can be defined in terms of other constructs. The original definition of Lisp defined the language by giving a definition of the interpreter written in Lisp. To me this seems an effective means for explaining the semantics of the language to someone who knows a little of the language in the first place. BTW this is the same Henry Baker who devised the first incremental garbage collection algorithm which uses "to" and "from" spaces and a write barrier to get its incremental collections.