Lambda is not just a Greek letter

11 May 2006

Sometimes the planets in the heavens align themselves just right and a post you wanted to write is suddenly supported by a whole slew of news articles on the same day. Well, it just happened to me.

First, there's news of a new CTP of C# and LINQ, or to give it its full title "Microsoft Visual Studio Code Name “Orcas” Language-Integrated Query, May 2006 Community Technology Preview".

LINQ is interesting to me because not only does it give you an integrated way of doing queries across many sources of data, but it also incorporates a complete new language inside of C#, lambda expressions, in order to succinctly express anonymous methods.

Lambda expressions are derived from lambda calculus, a branch of mathematical logic. A lambda expression is essentially an anonymous method with a set of parameters and a block of code that applies to those parameters, yielding a result. They're interesting because the programming language that encompasses them enables you to use lambda expressions as data and pass them around to other methods as parameters. C# 2.0's anonymous delegates get close, but the syntax is still a little too awkward.

Here's an example. In DLINQ you can write a query in C# like this:

var q = from o in orders, c in customers
        where (o.ShipCity == "London") && (o.CustomerID == c.CustomerID)
        select new { o.OrderDate, c.CompanyName, c.ContactTitle, c.ContactName };

Parsing this a little, you can see that it's almost a SQL statement in reverse. But note also that it's not "real" C#: what would the C# 2.0 compiler do with "from o in orders" for example. The result of this expression is q, which is a list of some newly auto-generated type with four properties: OrderDate, CompanyName, ContactTitle, ContactName. (That's the reason for the var keyword by the way: there's no way for us to know ahead of time what the new type is going to be called.)

This actually gets compiled to something like this:

var q = orders
          .Where(o => o.ShipCity == "London")
          .SelectMany(o =>
             customers
               .Where(c => o.CustomerID == c.CustomerID)
               .Select(c => new { o.OrderDate, c.CompanyName, c.ContactTitle, c.ContactName }));

Getting closer to "real" C# now (well, OK, I just don't know how to split it up on several lines), apart from those expressions like:

o => o.ShipCity == "London"

What's this? Well, this is a lambda expression. It takes one parameter (the o, an item in the orders collection, actually an IEnumerable I think) and returns a boolean (the result of comparing o.ShipCity to "London"). The expression is acting as a predicate delegate for the Where() method.

The reason for using the lambda expression is twofold. First it's more compact, something that C-languages are famous for, and you don't have to worry about writing all the syntax around creating a new delegate of the right type. Second, it's extraordinarily easy to parse it in to an expression tree. So what? Well the code behind DLINQ is able to analyze these expression trees in order to ascertain the best SQL statement to execute to get the data. The very worse SQL to generate would be to analyze the expression step by step: "Retrieve all orders. Now call the Where() method to find all those records that have ShipCity as London. Now we have another list of orders, let's execute the SelectMany() method on them. And so on." Instead the DLINQ run-time will evaluate the expression trees and produce something like this:

exec sp_executesql
N'SELECT [t1].[CompanyName], [t1].[ContactName], [t1].[ContactTitle], [t0].[OrderDate]
FROM [Orders] AS [t0], [Customers] AS [t1]
WHERE ([t0].[ShipCity] = N'London') AND ([t0].[CustomerID] = [t1].[CustomerID])'

In other words, so that the whole selection thing is done in the database, where it should be.

That's just one great thing about lambda expressions in C# 3.0, but to get more understanding about why they're important, it's handy to know a functional programming language. The oldest and most well-known is probably Lisp (or its close cousin Scheme). In comes the second link for today, a very well-written essay on why knowing Lisp, or rather concepts such as "code is data", is important in order to be a better programmer.

And then the inestimable Don Box is excited about some new lambda expression support in the latest CTP. It won't make much sense until you're very familiar with passing and combining lambda expressions.

no comments
No Comments

Please login or register to post comments.