The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








I heart FeedBurner

Latest Diggs - Programming

Computers Blogs - Blog Top Sites

Site Hits

Total: 2,817,231
since: 19 Jan 2005

Lambda Lambda Lambda

posted Sat 20 May 06

As I mentioned briefly in a previous blog entry, Lambda functions are a new feature in C# 3.0/LINQ. To get a grasp of what a Lambda function is, you need to understand delegates first, since Lambdas are similar to delegates. A delegate is essentially a type-safe function pointer. You can declare a delegate's signature as follows:

public delegate void DoSomethingDelegate();

This creates a method signature with which delegate instance variables can be associated. Assume you have a method called ShowMessage, and you want to create a delegate (typesafe function pointer) for that method. If the method matches the signature for DoSomethingDelegate(), you can use the following line of code:

DoSomethingDelegate doSomething = new DoSomethingDelegate(ShowMessage);

Once you have a delegate, you can pass the delegate around as method parameters, unleashing a whole new world of patterns and practices that can greatly increase the power and flexibility of your applications. For example, if you have a long-running method that you want to periodically inform the GUI of its progress, you could do something like this:

LongRunningMethod( initialData, new ShowProgressDelegate(ShowProgress));

This would allow the ShowProgress method to be called by the LongRunningMethod method.

With C# 2.0 came anonymous methods which work really well with delegates when you want to create a delegate that you don't need to assign a name for - such as when you just need to assign a single line of code to a button's click event handler.

Even though it isn't immediately obvious from the examples available for LINQ, all of the query syntax functionality is made possible through the C# 3.0 language support for Lambdas. While the lambda implementation in C# isn't quite the same as the lambda implementation in pure-functional languages like ML, Scheme, and LISP - its still pretty darn impressive.

Take a look at this lambda:

x => x > 10

This lambda represents a boolean expression that returns true when x > 10 and false otherwise. You can pass lambda functions around much the same way you pass delegates around, and use them within LINQ queries (its hard to use a LINQ query without a lambda). The following syntax should look familiar to you if you read the previous blog entry:

var expr = from n in names where n.Length > 3 select n;

This is the same as creating your own lambda and using it within the query:

Func<string, bool> filter = name => name.Length > 3;
var expr = from n in names .Where(filter) select n.ToUpper();

Func<T,I> is a generic type that represents a lambda function that returns data of type T and accepts an input parameter of type I. Lambda functions are (as far as I've been able to tell) always single-parameter functions.

While this is all pretty impressive on its own, there is something going on here behind the scenes that is mind-blowingly cool. The expressions you create with the query syntax or manually using the language extensions directly can actually build an in-memory expression tree. What this means is that code is being treated as data. The concept of code being data and data being code is one of those things that fried my brain in college when using LISP and Scheme, and I loved it. When you attempt to utilize the expression tree that was created, the expression tree is then compiled into something that is truly executable.

For example, when you write DLinq (more on that in upcoming blog entries) queries, C# is actually deferring the execution of the query. This allows the entire query to be build in terms of an expression tree. When results are requested from the expression, DLinq performs its magic on the expression tree and determines the most appropriate SQL query to execute - avoiding the common OR/M pitfall of doing client-side joins that plague the application genre.

You can create an expression tree from a lambda manually using the Expression<T> class:

Expression<Func<int, bool>> isEven = operand => (operand & 1) == 0;

You can then examine the contents of the expression tree at runtime, compile the expression into an executable delegate, and invoke the lambda function manually or pass it into a (D/X/)Linq query:

BinaryExpression be = (BinaryExpression)isEven.Body;
ConstantExpression right = (ConstantExpression)be.Right;
Console.WriteLine("Right side value is : " + right.Value);
 
Console.WriteLine("9 is even? " +
    isEven.Compile().Invoke(9).ToString());

I can't stress how important this simple fact is: When building LINQ queries, you are actually building Expression Trees that may or may not defer execution until a later time based on the syntax of your query. Deferring execution in DLing queries allows DLinq to optimize a query containing multiple nested queries into the fewest number of efficient SQL statements as possible.

Deferred execution allows the language extensions for XLinq, DLinq, LINQ, or any other *Linq extension that comes after to process the logic represented by the expression tree before execution so that optimizations can take place.

If you are planning on doing anything with LINQ, you should know what a lambda is, how to use it, and what an expression tree is, and how they figure into LINQ queries. You may not need to know the ins and outs of traversing an expression tree, but knowing when you should allow LINQ to defer query execution and when you should force immediate execution can make the difference between a fantastic app and an app that may not even work.

tags:                

links: digg this    del.icio.us    technorati    reddit




Tag Related Posts

Smart, Deep Property Notifications in CLINQ v2.0

Tue 07 Oct 08 1:15 P GMT-05
tags:          

Microsoft's Lofty Direction

Sun 05 Oct 08 2:30 P GMT-05

So I'm in the LA Times ;)

Wed 27 Aug 08 2:51 P GMT-05
tags:                  

MobileMe vs. Live Mesh Throwdown - Round 1

Wed 16 Jul 08 10:33 A GMT-05

Building Model Classes in C# and Cocoa

Sun 15 Jun 08 3:13 P GMT-05
tags:            

NYC SharePoint Developer Needed

Mon 12 May 08 12:09 P GMT-05

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

One Framework to Rule them All

Mon 25 Feb 08 6:49 P GMT-05

LINQ to REST - A much better name for Astoria

Tue 11 Dec 07 1:23 P GMT-05
tags:        

Unexpected and Unsafe behavior in LINQ

Wed 14 Nov 07 8:09 P GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Continuous LINQ

Mon 06 Aug 07 1:21 P GMT-05
tags:    

Dynamic, Observable LINQ Views

Tue 31 Jul 07 1:21 A GMT-05
tags:        

The dreaded language bleed-over has begun

Tue 19 Jun 07 6:23 P GMT-05
tags:        

Installing Orcas Beta 1 - VMware Style

Mon 23 Apr 07 12:16 P GMT-05

Core Data - Almost too Easy?

Wed 18 Apr 07 2:23 P GMT-05

Will Silverlight be DOA?

Mon 16 Apr 07 8:02 P GMT-05

My Little Pony .NET Unleashed 2007

Fri 30 Mar 07 1:59 P GMT-05

An experience with the Leopard beta

Mon 26 Mar 07 7:45 P GMT-05
tags:                

Authorness

Thu 15 Mar 07 1:44 P GMT-05

Visual Studio "Orcas" - March CTP is Available

Wed 28 Feb 07 12:28 P GMT-05
tags:            

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05

DLinq vs the ADO.NET Entity Framework

Fri 23 Jun 06 4:01 P GMT-05

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags:                  

Language Extensions in C# 3.0

Wed 31 May 06 2:17 P GMT-05

Lambda Lambda Lambda

Sun 21 May 06 1:01 A GMT-05