Blog - Title

Lambda Expressions

Lambda Expressions

  • Comments 67

[Blog Map]  [Table of Contents]  [Next Topic]

Note: This article is a topic in a much larger tutorial on writing pure functional code in C#.  Lambda expressions are only one of the pieces in a much larger puzzle.  Functional programming in C# allows us to write shorter programs that perform better, and are much more robust.  Query Composition using Functional Programming Techniques explains lambda expressions in their proper context.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOC
In order to learn functional programming and a more declarative style of writing code, we need first to cover some basic material.  One of the first concepts is that of lambda expressions.  Lambda expressions can be summarized in one sentence:

Lambda expressions are simply functions/methods.

They have a different syntax, primarily so that they can be written in expression context (more on this shortly) instead of as a member of a class.  However, that is all they are.  For instance, the following lambda expression:

c => c + 1

is a function that takes one argument, c, and returns the value c + 1.

Actually, they are slightly more complicated than this, but not much more.  For the purposes of this tutorial, you only use lambda expressions when calling a method that takes a delegate as a parameter.  Instead of writing a method, creating a delegate from the method, and passing the delegate to the method as a parameter, you can simply write a lambda expression in-line as a parameter to the method.

To show lambda expressions in context, consider the problem where you have an array with 10 digits in it, and you want to filter for all digits greater than 5.  In this case, you can use the Where extension method, passing a lambda expression as an argument to the Where method:

int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };
 
foreach (int i in source.Where(x => x > 5))
    Console.WriteLine(i);

To understand the semantics of this code, you needn't find some method elsewhere in the source code that does the selection; the code that you need to read is much tighter and smaller.  It reflects your intent in a much cleaner fashion.

Later on in this tutorial, you'll see a number of uses of the standard query operators.  Many of the standard query operators, including Where, take delegates as an argument, so this means that we can call them passing a lambda as an argument.

First, a quick review of delegates:

Defining, Creating, and Using a Delegate

In C#, a delegate is a data structure that refers to either a static method, or an object and an instance method of its class.  When you initialize a delegate, you initialize it with either a static method, or a class instance and an instance method.

The following code shows the definition of a delegate and a method that can be used to initialize the delegate:

// Defines a delegate that takes an int and returns an int
public delegate int ChangeInt(int x);
 
// Define a method to which the delegate can point
static public int DoubleIt(int x)
{
    return x * 2;
}

Now, you can create and initialize an instance of the delegate, and then call it:

ChangeInt myDelegate = new ChangeInt(DelegateSample.DoubleIt);
Console.WriteLine("{0}", myDelegate(5));

This, as you would expect, writes 10 to the console.

Using an Anonymous Method

With C# 2.0, anonymous methods allow you to write a method and initialize a delegate in place:

ChangeInt myDelegate = new ChangeInt(
    delegate(int x)
    {
        return x * 2;
    }
);
Console.WriteLine("{0}", myDelegate(5));

Using a Lambda Expression

With Lambda expressions, the syntax gets even terser:

ChangeInt myDelegate = x => x * 2;
Console.WriteLine("{0}", myDelegate(5));

This lambda expression is an anonymous method that takes one argument x, and returns x * 2.  In this case, the type of x and the type that the lambda returns are inferred from the type of the delegate to which the lambda is assigned.

If you wanted to, you could have specified the type of the argument, as follows:

ChangeInt myDelegate = (int x) => x * 2;
Console.WriteLine("{0}", myDelegate(5));

Using a Lambda with Two Arguments

When using the Standard Query Operators, on occasion, you need to write a lambda expression that takes two arguments.

If you have a delegate that takes two arguments:

// Defines a delegate that takes two ints and returns an int
public delegate int MultiplyInts(int arg, int arg2);

You can declare and initialize a delegate:

MultiplyInts myDelegate = (a, b) => a * b;
Console.WriteLine("{0}", myDelegate(5, 2));

Statement Lambda Expressions

You can write a more complicated lambda expression using statements, enclosing the statements in braces.  If you use this syntax, you must use the return statement, unless the lambda returns void:

int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };
 
foreach (int i in source.Where(
        x =>
        {
            if (x <= 3)
                return true;
            else if (x >= 7)
                return true;
            return false;
        }
    ))
    Console.WriteLine(i);

Sometimes developers wonder how to pronounce the => token.

If the lambda expression is a predicate, expressing some condition: c => c.State == "WA" then the => can be spoken as "such that".  In this example, you could say "c such that c dot state equals Washington".  If the lambda expression is a projection, returning a new type: c => new XElement("CustomerID", c.CustomerID); then the => can be spoken as "becomes".  In the above example, you could say "c becomes new XElement with a name of CustomerID and its value is c dot CustomerID".  Or "maps to", or "evaluate to", as suggested in the comments below.  But most often, I just say "arrow".  J

A quick note: predicates are simply boolean expressions that are passed to some method that will use the boolean expression to filter something.  A lambda expression used for projection takes one type, and returns a different type.  More on both of these concepts later.

Lambda Expressions that Return Void

A lambda expression that returns void is not very useful in the context of functional programming because the only possible reason for such a function is that it has side-effects, and is not pure (more on this later in the tutorial), but it is part of C# 3.0 syntax, so I'll cover it here.  Sometimes developers will use a void statement lambda expression for writing an event handler.  This has the benefit that the syntax is terser, and the program is smaller.  In addition, the lambda expression can refer to local variables in the enclosing scope.  This is part of C#'s implementation of closures.  The only way to write a lambda expression that returns void is to write a statement lambda expression.  The following example shows defining a void delegate, declaring an instance of it, and calling it.

// Defines a delegate that takes a string and returns void
public delegate void OutputToConsole(string arg);
 
static void Main(string[] args)
{
    OutputToConsole o = a => {
        Console.WriteLine(a);
    };
    o("Hello, World");
}

If you write a lambda expression for a delegate that returns void and takes no arguments, it results in interesting syntax:

// Defines a delegate that takes no arguments and returns void
public delegate void OutputHelloToConsole();
 
static void Main(string[] args)
{
    OutputHelloToConsole o = () =>
    {
        Console.WriteLine("Hello, World");
    };
    o();
}

The Func Delegate Types

The framework defines a number of parameterized delegate types:

public delegate TR Func<TR>();
public delegate TR Func<T0, TR>(T0 a0);
public delegate TR Func<T0, T1, TR>(T0 a0, T1 a1);
public delegate TR Func<T0, T1, T2, TR>(T0 a0, T1 a1, T2 a2);
public delegate TR Func<T0, T1, T2, T3, TR>(T0 a0, T1 a1, T2 a2, T3 a3);

In the above delegate types, notice that if there is only one type parameter, it is the return type of the delegate. If there are two type parameters, the first type parameter is the type of the one and only argument, and the second type is the return type of the delegate, and so on. Many of the standard query operators (which are just methods that you call) take as an argument a delegate of one of these types. These delegate definitions are useful to you when writing your own methods that take a delegate as an argument.

using System;
using System.Collections.Generic;
 
class Program
{
    static List<T> MyWhereMethod<T>(IEnumerable<T> source,
        Func<T, bool> predicate)
    {
        List<T> l = new List<T>();
        foreach (T item in source)
            if (predicate(item))
                l.Add(item);
        return l;
    }
 
    static void Main(string[] args)
    {
        int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };
 
        List<int> filteredList = MyWhereMethod(source,
            i => i >= 5);
        foreach (int z in filteredList)
            Console.WriteLine(z);
    }
}

The Action Delegate Types

The framework defines a number of parameterized delegate types for delegates that return void:

public delegate void Action();
public delegate void Action<T0>(T0 a0);
public delegate void Action<T0, T1>(T0 a0, T1 a1);
public delegate void Action<T0, T1, T2>(T0 a0, T1 a1, T2 a2);
public delegate void Action<T0, T1, T2, T3>(T0 a0, T1 a1, T2 a2, T3 a3);

Sometimes API designers will include an event that takes one of these delegate types as an argument, and you can write a lambda expression for the argument.  As with the Func delegate types, these delegate definitions are useful to you when writing your own methods that take a delegate as an argument.  This uses the interesting syntax of () => { /* body of void function here */ };

using System;
using System.Collections.Generic;
using System.Threading;
 
class Program
{
    static void SomeAsynchronousMethod(Action complete)
    {
        // just pretending to be asynchronous in this example
        Thread.Sleep(1000);
        complete();
    }
 
    static void Main(string[] args)
    {
        SomeAsynchronousMethod(() => { Console.WriteLine("Done"); });
    }
}

Expression Trees

Lambda expressions can also be used as expression trees.  This is an interesting topic, but is not part of this discussion on writing pure functional transformations.

[Blog Map]  [Table of Contents]  [Next Topic]

Leave a Comment
  • Please add 8 and 1 and type the answer here:
  • Post
  • Thanks for the very clear explanation!

    What I am additionally looking for is the c# specification that explains why the following code, taken from your example above, works:

       static List<T> MyWhereMethod<T>(IEnumerable<T> source,

           Func<T, bool> predicate) {...}

    ...

          int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

          List<int> filteredList = MyWhereMethod(source,

               i => i >= 5);

    How does the resolving work for the function-call with signature List<int> MyWhereMethod(IEnumerable<int>, Func<T, bool>)?

    There isn't such a signature in this namespace, at least not literally. Contrary to my expectations the compiler apparently is smarter than I thought and resolves to the given MyWhereMethod<T>.

    Why is that?

  • @Benjamin,

    The syntax that you're asking about is how you write an anonymous method in C# 2.0.  Because ChangeInt takes a delegate as an argument, it is valid to use the delegate keyword to write an anonymous method in-line, and pass it to the method.  Lambda expressions are simply more terse syntax for writing an anonymous method.

    @Carl,

    This works because of the type inference that comes into play with generic methods.  (Generic methods are those that are defined with a type parameter, i.e.  List<T> MyWhereMethod<T>(IEnumerable<T> source, Func<T, bool> predicate).  Type inference for generic methods is defined in section 7.4.2 of the C# 3.0 specification.  The C# compiler goes through a specific set of steps when determining which method can bind to a method call, and which binding will have the highest priority, and will get the binding.  Because the name is MyWhereMethod in the method call, and that is the name of the method, that method call will go through the type inference algorithm to decide whether the compiler can bind to the generic method.  The first step in deciding whether the compiler can bind to the method is to infer the type of the generic parameter.  The source argument is an array of integer, which implements IEnumerable<int>, so the compiler can infer the type of int for T, and see if the method binds properly.  It then infers the type of i in the lambda expression as int, and infers the return type of List<int>, which exactly matches the value to the left of the equals sign.  When the compiler infers T as int, because everything compiles properly, the compiler can then bind the method call to the generic method.

    -Eric

  • Thanks for trying to explain, though this confuses me. You wrote: "Because ChangeInt takes a delegate as an argument". But I see that it takes an int, named x:

    public delegate int ChangeInt(int x);

    As far as I understand, you have a delegate named ChangeInt, to which you pass yet another delegate, that has a anonymous method:

    ChangeInt myDelegate = new ChangeInt(delegate(int x)

    {

     return x * 2;

    }

    What does "initialize a delegate in place" mean? I thought you already defined a delegate (ChangeInt) and initialized it with this line: new ChangeInt.

  • Hi Benjamin,

    Sorry, I didn't take the proper time to write the last answer.  Here is how this works:

    // the following is the *definition* of a delegate type

    public delegate int ChangeInt(int x);

    // the following is a *declaration* of a delegate

    ChangeInt myDelegate = new ChangeInt(

       delegate(int x)

       {

           return x * 2;

       }

    );

    In a declaration, when newing up the instance of a delegate, you can pass the name of a method that has the correct signature, which is how the example immediately preceding the one that we're discussing works.  Or when newing up the instance of a delegate, you can write an anonymous method right there, in place.  This uses the delegate keyword, where you declare the types of the arguments and the body of the method immediately following 'delegate'.

    Does that make sense?

    -Eric

  • I think I do. In the second example there is not yet a definition of a delegate, but you make one with

    ChangeInt myDelegate = new ChangeInt(delegate(int x)  {return x * 2;});

    If that's correct, than I understand. Thank you very much for taking the time Eric!

  • While fiddling with code, I noticed you can also write this:

    public delegate int ChangeInt(int x);

    ChangeInt myDelegate = delegate(int x) { return x * 2; };}

    It produces the same output, no errors. Is there any difference between the two?

  • Hi Benjamin,

    No, there is no difference between the two.  The compiler can initialize the delegate with the anonymous method that you create with the delegate keyword.  This is similar to code that you could write like this:

    ChangeInt myDelegate = (int x) => { return x * 2; };

    or

    ChangeInt myDelegate => x => x * 2;

    For what its worth, I never use the delegate keyword, as you can always use the lambda expression syntax.  After you become accustomed to lambda expression syntax, it becomes more natural, in my opinion.

    -Eric

  • Excellent article! You made it so easy to understand.  Thank you so much!

  • Thanks Eric for the Nice Article.

  • Thanks for the article, it helped clear a few things up for me!

    I have a question though and I may be completely missing something here, but take the following code from the article:

    int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

    foreach (int i in source.Where(x => x > 5))

        Console.WriteLine(i);

    Is there an advantage to using Lambda to extract data from the array rather than LINQ?

  • Hi Andrew,

    Query expressions are directly translated to equivalent expressions using lambda expressions.  The nomenclature is that when you express them using lambda expressions, they are written in 'method syntax'.

    For example, another way to write the query that you referred to is like this:

    int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

    var q = source.Where(x => x > 5);

    foreach (int i in q)

        Console.WriteLine(i);

    This is exactly the same as if you write this:

    int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

    var q = from x in source

            where x > 5

            select x;

    foreach (int i in q)

        Console.WriteLine(i);

    The second form is translated to the first by the compiler.

    I've written a few things that discuss this:

    http://blogs.msdn.com/ericwhite/pages/Quick-Intro-to-Query-Expressions.aspx

    http://blogs.msdn.com/ericwhite/pages/an-example-presented-in-both-coding-styles.aspx

    http://blogs.msdn.com/ericwhite/pages/statically-compiled-queries.aspx

    For what it's worth, I have gravitated completely to using 'method syntax'.  There are queries that you can write in method syntax that you can't write using query expressions, but the reverse is not true, so I personally find it more convenient to consistently use method syntax. 

    -Eric

     

  • Thanks a lot EricWhite for your efforts. Your tutorial is so simple yet so authoritative. Its a breeze to learn lambadas/FP through your tutorial(s). Would you care to write some day on Expression trees using lambadas as mentioned. In the mean time can you suggest some resources which are as good as yours for learning Expression trees through FP.

    -Panks

  • Hi Panks, I'm glad it's useful.  The SharePoint 2010 managed client side object model (CSOM) includes an interesting use of lambda expressions that are processed by expression trees.  I'm planning on writing a blog post/MSDN article that explains that use of lambda expressions.  It would be fun to also write a more general explanation of expression trees.

    -Eric

  • I loved reading this. Now I know lambda.

    Thanks everyone

  • Really good article to understand Lamda Expression

Page 4 of 5 (67 items) 12345