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?"
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);
}
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.
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)
});
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...
bool (Llama llama)
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.
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...
(Llama llama)
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;
(llama)
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?
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;
Llamas.Where( (llama) => llama.IsGrumpy && llama.Height > 9 );
Now we don't need the brackets around our input parameter as there's only one...
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 );
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!
Nice explanation. I'm new to C#, so I appreciate it very much.
Thank you,
Richard
@ 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
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
Thanks Terry! Really appreciate the feedback.
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.
so, if we know what the subject is, why mention it? Why not this?
var results = Llamas.Where(IsGrumpy && Height > 9 );
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?
Digital Media Minute pointer of the day. Nice job.
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.
@ 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 :-)
Great explanation - very helpful.
Thanks Mike!
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!)
@ Joel;
LOL!!! Gotta love Monty Python. I'd completely forgotten about that sketch, apart from subconciously presumably.
"Look out there are Llamas".
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.