Lambda Expressions in 5 Minutes



You don’t need a course in advanced calculus to understand Lambda Expressions.  In fact, you can learn the basics in 5 minutes or less.  To accomplish this, we are going to revise a code snippet for an event handler from .Net 1.1 syntax to a syntactically sweet Lambda Expression.  Before we jump to the code, let’s define some basic terms for this exercise:


Delegate
A type that references a method (or a strongly-typed function pointer in c++ terms).  The following variable of type EventHandler contains a reference to a method I would like run when Button1 is clicked.


Named Method
A method with a name.  When Button1 is clicked, execute the following named method “Button1_ClickHandler.”


Anonymous Method
A method without a name.  When Button1 is clicked, execute the following statement(s): MessageBox.Show(“You clicked Button1!”);


Anonymous Function
An anonymous method that returns a value.


Lambda Expression
An expression syntax for an anonymous function.


Enough talk, let’s get to the code.  Although not the best example to showcase the application of delegates and Lambda Expressions, I think most developers understand event handlers so that is what we will use for this exercise.  Suppose you have a Windows Form with a Button on it.  You want to run some code whenever the button is clicked.

Revision 1: .Net 1.1 named method and delegate instantiation
button1.Click += new EventHandler(Button1_Click);
void Button1_Click(object sender, EventArgs e)
{
Debug.Print(“Button1 click handled by named method.”);
}

A named method “Button1_Click” is created and a new Event Handler is instantiated passing in the named method.


Revision 2: .Net 2.0 named method and delegate inference

button1.Click += Button1_Click;
void Button1_Click(object sender, EventArgs e)
{
Debug.Print(“Button1 click handled by named method and delegate inference.”);
}

A named method “Button1_Click” is created and the delegate type is inferred by assigning it directly to the event.


Revision 3: .Net 2.0 anonymous method

button1.Click += delegate(object sender, EventArgs e)  { Debug.Print(“Button1 click handled by anonymous method.”); }

The keyword delegate is used to “inline” the statements that should be executed when the button is clicked.

Revision 4: .Net 3.5 Lambda Expression

button1.Click += (object sender, EventArgs e) => Debug.Print(“Button1 click handled by lambda expression.”); 

The Lambda operator => is used.   You can read the operator as “goes to” or “is passed to.”

Revision 5: .Net 3.5 Lambda Expression with type inference

button1.Click += (sender, e) => Debug.Print(“Button1 click handled by lambda expression with type inference.”); 

The parameter types (sender, e) are inferred.

Beyond Event Handlers

Let’s examine an application of Lambda Expressions other than event handlers.  Suppose you have a list of names and you want to find all names that start with J.  The List class has a FindAll method that is useful for this purpose.  This method enumerates through the list items and for each one, calls a function that you specify to determine if the item meets the search criteria.

List<string> names = new List<string>() { “john”, “bob”, “harry”, “sally”, “juno” };
List<string> namesThatStartWithJ = names.FindAll((name) => name.StartsWith(“j”));
 

I hope this example was helpful for demonstrating the basics of Lambda Expressions, but please remember this is an example.  I am not recommending changing all of your event handlers to anonymous methods!  Lambda Expressions should be used to make your code more expressive, succinct, readable and maintainable.  Sure, they are cool, but don’t use them just because they are and you can! 


Further Reading


If you want to learn more about Lambda Expressions, here are some additional resources:



References



Comments (5)

  1. Anders Borum says:

    As far as I’m concerned, Lambda expressions were supported from the release of .NET 3.5, not .NET 3.0 as is mentioned in the article. Aside from that I think the examples are very clear and easy to understand for most developers.

  2. EricLippert says:

    Good article, one minor nitpick — "anonymous function" is not defined as an anonymous method which returns a value. Rather, we needed a way in the specification to express the following concepts:

    * A "traditional" anonymous method, but not a lambda expression

    * A lambda expression, but not a "traditional" anonymous method

    * Either a lambda expression or an anonymous method.

    The terms we chose for the v3 specification are:

    * anonymous method

    * lambda expression

    * anonymous function

    So when you see "anonymous function" in the spec, it means "either an anonymous method or a lambda expression".

    This is a bit confusing, I agree, but we couldn’t come up with a better term.

  3. John Hamm says:

    You should add Revision 6 and show that it is even simpler if your lambda expression takes one parameter:

    List<string> namesThatStartWithJ = names.FindAll(name => name.StartsWith("j"));  

  4. David W says:

    This is a dandy, bite-size intro to lambda expressions. Given that they inherently leverage inline anonymous delegates and introduce a syntax that might twist your eyes at first glance, this intro is a terrific starting point with good illustrations. Kudos!

    For those who have not quite made the leap to the Exists and FindAll (and kindred) methods of List<T> objects, it might not be immediately obvious that there are chances for considerable code consolidation with lambda expressions…no iteration lace-up code, better chance to write intentional code, and fewer lines to wade through in maintenance.

    Great stuff, and a dandy new tool to have in the toolbox.