What on Earth is a Lambda Expression?


Recently I've spoken with a few customers that have asked what a Lambda Expression is, which surprised me. It seems that a second wave of developers  are now starting to use Lambdas (i.e. those that didn't adopt C# 3.0 immediately) and need some pointers, so this post is intended to help you understand what they represent.


I'm not going into the how, why, where, and more here – there are better posts that do. This is just "what the heck does that syntax mean?"


An Example Situation


I'm going to use an example common to software development in the modern world – filtering a list of Llamas according to their height and how prone to grumpiness they are (OK, perhaps only fairly common, and yes, I'm writing this on a Friday afternoon J).


Imagine we have a list of our favourite Llamas;


private static List<Llama> Llamas = new List<Llama>()


{


    new Llama { Name = "Larry", Height = 10, IsGrumpy = true },


    new Llama { Name = "Loulou", Height = 12, IsGrumpy = false },


    new Llama { Name = "Lara", Height = 8, IsGrumpy = true },


    new Llama { Name = "Lorry", Height = 4, IsGrumpy = true },


    new Llama { Name = "Laurel", Height = 20, IsGrumpy = false },


    new Llama { Name = "Louise", Height = 17, IsGrumpy = true }


};


Now imagine that I want to get a list of all Llamas that are both Tall and prone to Grumpiness. We might achieve that like this;


var results = new List<Llama>();


foreach (var llama in Llamas)


{


    bool include = llama.IsGrumpy && llama.Height > 9;


    if (include)


        results.Add(llama);


}


Refactoring to a Lamda


The problem is that's a lot of code to do some simple filtering...  and we know there are these great Extension Methods in LINQ that allow us to do a Where command on a collection of objects.


Let's make some changes to the syntax to start heading in the right direction. Note that much of the content in the rest of this post is intentionally invalid C# syntax – I'm leading you to the solution. I'll call out the next time it becomes valid syntax again!


Imagine that Where took as input the name of a method to perform filtering of a list. Perhaps our code would look like this;


var results = Llamas.Where(Filter);


... and a helper method named Filter;


private bool Filter(Llama llama)


{


    return llama.IsGrumpy && llama.Height > 9;


}


That makes sense right? The Where method calls the Filter method with each Llama to check if it should be included in the results.


Anonymous Inline Methods


But our Filter method is only ever used by this single line of code to filter our Llamas, so we could just not bother declaring a separate method, and use an inline one instead, perhaps something like this (again, this isn't valid syntax like much of this post)...


var results = Llamas.Where(


bool Filter(Llama llama)


{


return llama.IsGrumpy && llama.Height > 9;


});


Here you can see we've in-lined the method, and gotten rid of the private keyword as it's no longer a class member. But why does it have a name then? Let's lose the name...


var results = Llamas.Where(


bool (Llama llama)


{


return llama.IsGrumpy && llama.Height > 9;


});


Our syntax is getting pretty concise, so stay with me... all this says is "this method returns a Boolean, and requires a Llama as input", and then defines the method body.


Implied Types


But the C# compiler is pretty smart right? So why am I telling it that this returns a Boolean, when it knows the Where method needs a Boolean, and it can check that the "IsGrumpy && Height > 9" statement is a Boolean expression? Let's lose that bool keyword...


var results = Llamas.Where(


(Llama llama)


{


return llama.IsGrumpy && llama.Height > 9;


});


And we also know that the Where method is operating on a List<Llama>, so the only possible input to this method is of type Llama... so let's stop needlessly calling this out in our code;


var results = Llamas.Where(


(llama)


{


return llama.IsGrumpy && llama.Height > 9;


});


Needless Constructs


The thing is, our method is such a simple single line Boolean expression, why do we need the return keyword? Or the semi-colon terminating the line? We know that's what it is doing. And we don't need the braces for a single line expression right?


var results = Llamas.Where(


(llama)


llama.IsGrumpy && llama.Height > 9


);


The problem is that if we remove some white space;


var results =


  Llamas.Where( (llama) llama.IsGrumpy && llama.Height > 9 );


... it gets pretty tough to read, so we need a new way of separating the input parameters from the body of our expression, and in C# that is the => operator;


var results =


  Llamas.Where( (llama) => llama.IsGrumpy && llama.Height > 9 );


Now we don't need the brackets around our input parameter as there's only one...


var results =


  Llamas.Where( llama => llama.IsGrumpy && llama.Height > 9 );


... and why use all those characters to spell out "llama" all the time when we could use "l"?


var results = Llamas.Where( l => l.IsGrumpy && l.Height > 9 );


Summary


It turns out that the last three statements above are valid Lambda Expressions that filter a list of Llamas for us. The intention of this code hasn't changed – it is still saying;


Here is a method that takes an input parameter named "l", and returns a Boolean result by executing the following expression against that parameter. Use this method to filter Llamas please!


So explain to yourself what this syntax would mean?


tallGrumpyLlamas.ForEach(l => Console.WriteLine(l.Name));


I really hope this has been a slightly different approach to explaining how to use Lambda Expressions... of course you should now do some reading up to understand related things like Expression<>, Func<>, Action<>, and more... enjoy!

I've attached the simplest example code in case you want to play with it yourself.

Program.cs

Comments (29)

  1. Richard says:

    Nice explanation.  I’m new to C#, so I appreciate it very much.

    Thank you,

    Richard

  2. Simon J Ince says:

    @ Richard;

    my pleasure – happy you found it useful. I think sometimes explanations get caught up in the detail of how they work behind the scenes, and forget to talk about the basics.

    Simon

  3. Terry Brown says:

    fantastic explanation Simon.  I’ve been using lambdas for years and find them incredibly powerful and concise constructs.

    Will forward this post onto the team I work with as not all of them are fans of lambdas and I think the above is one of the best explanation I’ve seen.

    Cheers,

    Terry

  4. Simon J Ince says:

    Thanks Terry! Really appreciate the feedback.

    Simon

  5. Rodney says:

    I moved from C# to Ruby and Rails. This, along with MVC, Castle, etc. is a good change of direction. Will make the transition back, if ever, much easier.

  6. florin says:

    so, if we know what the subject is, why mention it? Why not this?

    var results = Llamas.Where(IsGrumpy && Height > 9 );

  7. I have been using lambda in production code for the last three or four months.  I am getting some feedback that this code is harder to understand that more traditional C#.

    What is your opinion on this?

  8. Tom says:

    Digital Media Minute pointer of the day. Nice job.

  9. Not to mention that closures and collections go well very well (http://bit.ly/aR2nW). It is good to see that, along with Java getting closures, the awareness of this powerfull concept is rising.

  10. Simon J Ince says:

    @ Rodney,

    Great news – and I agree with you… I love MVC, the new language features in C#, etc.

    @ florin,

    Because many lambdas have more than one input parameter, so it needs to be named… and because you might choose to access members on objects other than the single input parameter (assuming you only had one). I also think your approach is a bigger deviation from standard C# syntax. I see why you suggest it though – simplest is best in most cases, but I think the implementation is a good balance in this case.

    @ Dennis,

    I think that’s common feedback for new language features, and you need to balance their use against your development team’s experience. Having said that I also think Lambdas are easy to grasp if you just spend 30 minutes looking into them so that shouldn’t be a big obstacle.

    In the vast majority of cases Lambdas hugely increase the readability of code too – in the example on this page the mechanism of expressing how to filter a list is way better than manually iterating through the collection. I guess the trick is to make sure you use them appropriately.

    In other words, my opinion is that they should do the opposite – improve code readability and maintainability – when used well, and when the dev team have been given time to get up to speed.

    @ Tom,

    Thanks!!

    @ Daniel,

    I agree… although I’m tempted to quote a film here about the balance of power and responsibility; closures are great but they can hurt your head 🙂

  11. MIke says:

    Great explanation – very helpful.

  12. Joel says:

    Frog tiny = new Frog {Height = 0.1};

    //¡Las llamas son mas grande que ranas!

    var results = Llamas.Where( l => l.Height > tiny.Height);

    // Which reminds me… why did I

    // call my frog "Tiny"? :o) (I’m here

    // all week. Please try the fish!)

  13. Simon J Ince says:

    @ Joel;

    LOL!!! Gotta love Monty Python. I’d completely forgotten about that sketch, apart from subconciously presumably.

    "Look out there are Llamas".

    Simon

  14. Prem says:

    Neat explanation of Lambda expression.. I had hard time explaining lambda expressions to some of my team members, I could use your logic to teach them. thanks for sharing.

  15. Donnie Hale says:

    I’ve seen examples and explanations of lambdas along these lines quite a bit. What seems to be most confusing to me is how the "l" (each llama in the list of llamas) gets projected out of item in the list. There’s an implicit for..each in there someplace – probably the implementation of the Where extension method. And many uses of lambdas don’t involve LINQ-style expressions. So how do I cement this concept of something being "projected" (perhaps overloading a word improperly) into the parameter(s) to the lambda expression within the context of where the lambda is being used?

  16. Simon,

    Such an elegant explanation. Congratulations.

    Mau

  17. Simon J Ince says:

    @ Donnie,

    This "projection" you mention is done by the Where method… the logic inside the method is something like;

    foreach (var l in llamas)

    {

      if (lambdaExpression(l))

         results.Add(l);

    }

    This means that it is the responsibility of the Where method to specify what signature the lambda expression must adhere to – obviously methods other than Where (such as ForEach or your own custom ones) might need different parameters.

    It turns out that Where does this by requiring the following type as the lambda expression parameter;

    Func<Llama, bool>

    This means "pass me a function that takes a Llama as input and returns a bool". The C# compiler validates that my expression fits this format.

    If writing my own Where-like function I could do this;

    public void CostProducts(

      Product prod1,

      Product prod2,

      Func<Product, Product, Int32> comparer)

    {

      // logic

    }

    The Func<Product, Product, Int32> states that I want a lambda expression that takes two products as input and returns an integer… so it might look like this in use;

    myobj.CostProducts(

      p1,

      p2,

      (prod1, prod2) => prod1.Cost + prod2.Cost);

    There is also Action<>, that does the same as Func<> but needs no return value (i.e. it is a Sub not a Function in VB-speak!).

    I hope that helps – this is why I suggested reading up on Func<>, Action<>, and Expression<>.

    Simon

  18. DarthObiwan says:

    Another interesting aspect of C# related to lambdas are method groups.

    Say you have a function

    public void SendLlamaOutToPasture(Llama llamaToSend)

    {

     //hurl Llama with catapult.

    }

    You would normally write it out something like the following

    tallGrumpyLlamas.ForEach(l => SendLlamaOutToPasture(l));

    But C# provides an even more concise way to express this.

    tallGrumpyLlamas.ForEach(SendLlamaOutToPasture);

    As with Event handlers C# is able to see this is valid because the method matches the signature needed. It is behind the scenes converted to a function pointer and all is right with the world. 🙂 This works anywhere lambdas would work.

    For your more complex lambdas I recommend using this by refactoring the lambda into a method. Then you can actually unit test the lambda.

    Another interesting thing is returning a lambda from a method. I use this when dynamically building Where statements for complex queries. (Say an Advanced Search page)

    public Expression<Func<Llama,bool>> IsLlamaOld(Llama llama)

    {

     return l => l.IsGrumpy && l.Height > 9

    }

  19. adityah says:

    I’ve read so many articles out there to understand lambda expression and I haven’t understand it well until reading your article. Thanks a bunch! I hope you can write more stuffs like this

  20. Terence says:

    Great post. Have been using Lamda’s for a couple of years but this stilled helped me clarify the way I think about them.  

    Thanks Terence

  21. Rich Hewlett says:

    An excellent explanation of an often confusing subject for many. How about doing a series like this for other topics (e.g. delegates)?  

  22. Anthony Bobenrieth says:

    The way you explain it is really nice, and interesting. Thank you!

  23. HAA says:

    Great job of explaining the concept.

    Thanks.

  24. Sara says:

    This article is really amazing!Thank you!

  25. Sara says:

    This article is really amazing!Tank you!

  26. Pramodh says:

    Wonderful explaination. Had never understood these many years about this -> lambda expressions. it was always black box for me. But your simplest explaination is worth reading by all of us and understand ->.

    Now I have confidence on lamdba. I appreciate it a looooooooot and great work. Simply mind blowing when I  understood completely at the end of your explanation i felt "is this only this? so foolish of me that I did not understand till date"

  27. Simon J Ince says:

    Please you like it guys! I'm a firm believer that you don't truly understand something if you can't explain it in a simple way.

  28. Rajni says:

    Hello !! This way of exlaining lambda expression is superb…..!! thanks a lot !

Skip to main content