LINQ Farm: Lambdas


Lambdas are a simple technology with an intimidating name. They sound like they are going to be difficult to understand, but in practice prove to be relatively trivial.

LINQ has an almost inordinate need for its users to declare a large number of small, simple delegates. The architects of C# decided that forcing the users of LINQ to declare delegates using standard C# 2.0 delegate syntax was an overly verbose option. They wanted to find a shorter, more concise way to accomplish the same task.

The syntax they settled on looks like this:

Func<int, int, int> myLambda = (a, b) => (a + b);

This is a shorthand way of writing code which is semantically equivalent to the following:

public static int Add(int a, int b)
{
    return a + b;
}

Func<int, int, int> myDelegate = Add;

In the next few paragraphs I will compare these two ways of creating a delegate instance, and explain how they map back and forth.

It is obvious that the left hand side of the following two code fragments have the same meaning:

Func<int, int, int> myLambda = (a, b) => (a + b);
Func<int, int, int> myDelegate = Add;

But how can the right hand side be the same?

It turns out that that the expression on the right hand side of the first statement is a shorthand way of writing a method semantically equivalent to the Add method. Just to be clear, a lambda is not a reference to the Add method, it is second method that does the same thing as the Add method.

Here is the lambda:

(a, b) => (a + b);

And here is the Add method:

public static int Add(int a, int b)
{
    return a + b;
}

Here is the place in the Add method where we define the parameters it will take:

(int a, int b)

Here is the place in the lambda where we define the parameters that it will take:

(a, b)

Here is the place in the Add method where we define what it will return:

return a + b;

Here is the place in the lambda where we define what it will return:

(a + b)

As you can see, a lambda and a method do the same thing: they define a set of parameters and an executable body of code.

The type declarations for a lambda are resolved using a technique very similar to the one we employ for generic methods and generic delegates. To see how this works, look again at the full declaration for the lambda:

Func<int, int, int> myLambda = (a, b) => (a + b);

The generic delegate Func says that the method being implemented takes two integers as parameters, and returns an integer. The compiler takes this information and applies it to the lambda. Behind the scenes it resolves (a, b) to (int a, int b) and defines the function such that the body of the lambda (a + b) returns an integer. Thus we give the compiler enough information to convert our lambda into a method that performs the same action as the Add method.

The => symbol is called a lambda operator and is usually pronounced “goes to.” Thus the lambda above can be read as “a comma b goes to a plus b,” or “a and b goes to a plus b.”

Though you will rarely need to do so, you can explicitly declare the type of parameters to a lambda expression:

Func<int, int, int> f = (int a, int b) => (a + b);

For void functions that do not return a value, just use an empty set of parenthesis:

() => Console.WriteLine();

Lambdas have access to local variables:

public static void UseLocal()
{
    int n;
    Func<int> func = () => { n = 6; return n; };
    n = func();
    Console.WriteLine(n); // Outputs the number 6
}

You might be familiar with anonymous methods from C# 2.0. Semantically, anonymous methods and lambdas are identical, but the lambda syntax is easier to use. As a result, there is probably no reason for you to use anonymous methods in the future. Below is a lambda and anonymous method side by side:

Func<int, int, int> myLambda = (a, b) => (a + b);
Func<int, int, int> myAnonMethod = delegate(int a, int b)
{
    return a + b;
};

Both methods take two integers, add them together, and return the result. Commenting further on anonymous methods at this point would serve no purpose, since lambdas create the same result with less work.

In this post you have had a chance to look at lambdas. Their name is intimidating, and their syntax can be a bit confusing at first. Once you see beneath the facade however, this technology turns out to be relatively easy to master.

kick it on DotNetKicks.com

Comments (34)

  1. You’ve been kicked (a good thing) – Trackback from DotNetKicks.com

  2. Keith Farmer says:

    A nuisance, of course, is that var doesn’t like bare lambdas — it cannot tell whether the lambda should be an expression or a function without additional information.

    So helper methods can be useful:

    given

    Func<T, R> NewFunc<T, R>(Func<T, R> func) { return func; }

    Expression<Func<T, R>> NewExpr<T, R>(Expression<Func<T, R>> expr) { return expr; }

    you can then write

    var fun = NewFunc((int i) => i + 1);

    var expr = NewExpr((int i) => i + 1);

  3. ccalvert says:

    Thanks Keith. Good tips.

  4. Jack Bond says:

    I may have missed it, but is there a way to declare a lamba function that takes arguments but does not return a value?

  5. configurator says:

    Returning a value from a lambda is implicit. If you define the lambda:

    (str) => Console.WriteLine(str)

    It will take the str and return the return value of Console.WriteLine – which is void.

    Also, you can use lambdas for more than one operation, like anonymous delegates, by using { }

    (i) => {

       Console.WriteLine("Calculating f(" + i + ")");

       return f(i);

    }

  6. Jack: you would use an Action parameter type rather than a Func parameter type.

  7. Kris says:

    Hi Charlie,

    Nice article!

    I still use anonymous methods or delegates when there will be more then a few lines of code. How about you?

  8. Marlon Grech says:

    Hi there,

    nice article…. I blogged on the Expression part of the lambdas… have a look and see if you like it

    http://marlongrech.wordpress.com/2008/01/08/working-with-expression-trees-part-1/

  9. My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Greg Duncan posted a link to the DevExpress announcement of AgDataGrid Suite Beta 1 , available free of charge to Silverlight developers

  10. Ray says:

    Hi Charlie,

    This is a good explanation of lambdas. I’m going to update my post on lambdas to link to you.

    http://initializecomponent.blogspot.com/2008/07/fun-with-c-30-3-lambda-expressions.html

  11. Ted says:

    Anonymous delegates don’t pass our code quality requirements in code reviews and are not allowed in our production system unless there is a really really important reason to use one.

    Lambdas will follow the same stringent no-use requirement.

    We made this simplification because we had several developers use them in many many parts of our core applications not because they were needed but because they wanted to be overly creative with the code.

    This just made the existing systems significantly harder and therefore more costly to maintain given we shoot for code to be easily maintainable by someone with 1 to 2 years of experience.  

    It may be conterintuitive to use simpler language features but we’ve found that limiting code to basic language features and simple algorithms results in better code weighed over a 5+ year life-cycle.  

    We expend extra effort to put quality business logic/decision information in our code comments over fancier coding methods.  This has dramatically lowered the cost of our production systems measured out over their lifespan given that most of the cost of software systems comes after they first go into production (75% or more).  Therefore, the upfront costs to develop a new system can be a little higher if we get significantly least costly and easier to maintain systems once they are put into production.

  12. ccalvert says:

    Ted,

    I understand and respect your desire to keep your codebase simple and clean. Lambdas, however, are one of the technologies that enable LINQ, and LINQ queries can be a means of significantly simplifying a codebase. For instance, it is often possible to take a series of lengthy, nested for or while loops, and convert them into a single short, easy to maintain LINQ query expression that uses lambdas. By the same measure, LINQ to XML and lambdas can often be a much simpler alternative to long and hard to understand DOM, XQuery or XPATH statements, and LINQ to SQL can help eliminate hard to read and maintain code that contains embedded SQL strings that appear as string literals.

    The search for simplicity and clarity is necessary if one wants to write code that can be easily maintained, so I back your effort to achieve that goal. Still, new technologies such as LINQ are introduced into C# specifically to aid people who are trying to achieve the goals you outline. LINQ is an example of a new technology that enables developers to write code that is at once easier to read, easier to write, and easier to maintain.

    – Charlie

  13. Rob says:

    Ted,

    I am in a similar position to your developers. Anonymous delegates are pretty much banned on our projects because our architecture team doesn’t understand them (although they are honest enough to admit this). This makes our hopes of moving on to LINQ slim at best.

    This would not be much of an issue, except that LINQ, lambdas and associated technology are getting traction in the wider world.

    I fear that if things don’ change soon, I’ll have no choice but to find a way to get experience in those technologies, since getting stuck in an island of recalcitrance would be a bad career move.

  14. echostorm says:

    Ted,

     Have you considered that by enforcing juvenile coding standards that you are in effect both locking your developers into perpetual jr. developer status and more likely than not ensuring that only coders who are not overly interested in coding will be willing to work for you for very long.

     If you’re not moving forward, you’re falling behind. I certainly wouldn’t commit professional suicide to work for you.

  15. Jay Gray, Microsoft says:

    echostorm:

    Aren’t you being harsh? Are DB devs all "jr. developers" because the SQL language is intentionally minimized? It’s not just the commands you do/don’t use, but how you use them.

    Perhaps Ted’s devs would write a intro doc for lambda functions, with a proper usage guideline. Point to the lambda doc in the file headers of source files where lambdas are used + comments mentioning "// This lambda function creates …"

  16. Jay Gray, Microsoft says:

    Disclaimer: My opinions, not my employers…

  17. Joe says:

    Ted,  

    If your engineers are confused by anonymous delegates then perhaps they should sit down with a book and spend the 10-30 minutes it takes to master the concept.  Seriously, it isn’t exactly rocket science.

    Our company is taking the opposite approach and we are moving many of of our old .NET 1.1 and 2.0 projects to .NET 3.5.

    LINQ is the catalyst and personally, I get the shakes thinking about having to work on another .NET project without it.

    –Joe

  18. Ian says:

    Some people here seem to think that the technology itself is the point of a project, rather than the product they’re building.  I like to use the latest, coolest stuff as much as the next guy, BUT I’m very aware that it’s the business people who pay my wages and they value cheapness and speed in getting their desired end result, not the technology.  

    If a particular technology gives us speed and cost benefits, great, we’ll probably use it.  If it doesn’t, we won’t.  Any new technology will almost certainly start off in the ‘no we wont’ category because the learning curve and unfamiliarity counts against it.  It will have to show significant cost and speed benefits, or allow totally new solutions, in order to be justifiable.  Sytactic sugar, a new way of doing old things, isn’t really something that’s going to justify itself to me in the short term.  However, if it really allows us to benefit from LINQ (a technology we’re definitely interested in, since it allows for new types of solution and great cost benefits) in ways that we couldn’t without it, we’ll consider it.  

    Personally, I’m happy to get up to speed with a technology in my own time, so when it’s bedded down properly and when enough people are skilled with it we’ll be prepared to accept that the benefits outweigh the costs and we’ll start using it.  

    Not taking a job because someone won’t let you use lambdas sounds pretty daft to me!  I’d also be reluctant to take someone on who’s got such a narrow, technical view of things at the expense of a greater business perspective.

  19. Deepak says:

    Just the kind of explanation I was looking for. I have observed some discomfort among developers when Lambdas are mentioned. Your post puts it all in an easy to understand manner. Forwarding the link to all my team members.

  20. plissskin says:

    Really nice explanation of Lambdas and anonymous delegates, Charlie.  I hope you teach this stuff in some fashion, the industry needs you!

  21. Ad says:

    Hi,

    Thanks Charlie for such a nice article.

    In the same article I came to know diffrent views of People seating at diffent Positions in the Corporate ladder.

    Ted and Ian both have shared their views from the Business point of view.

    I will say both of them are correct at their place as they have to achive their goals.

    There are developers rather we can call them core techi guys who realy love to code diffrently in their own fashion [their developers who don’t like to code a single line too.; ].

    These techiee guys can realy solve some major/difficult problems in short span of time.

    and I think Lossing these peoples is not at all a good option from business point of view.

    In my career I have always seen that there is GAP between the Techi Guys (who love challenging tasks)

    and Business Oriented People (who love to get their job done with low cost and best quality.)

    I think both of them should think of a way where the needs of both can be met easily.

    It will help our Industry to grow in much better way.

    Have a great time ahead.

  22. ccalvert says:

    Thanks everyone for this interesting conversation. I feel like I should add that I frequently hear conversations here at Microsoft about the impediments people have when they consider adopting a new tool. When a strong technology like LINQ comes along, we all want to make it easy for people to start using it as quickly as possible, but that is not always a simple proposition. When something good comes along that requires a change in thinking, it seems like there is always a group of early adopters, followed by a mainstream, and then a group that gets left behind. I don’t think it is easy to pick one’s way through the various technical options that are available, but when we do make the right choices, it leads to very pleasing results.

  23. The LINQ aggregate operators allow you to perform simple math operations over the elements off a sequence.

  24. The LINQ aggregate operators allow you to perform simple math operations over the elements in a sequence.

  25. Enrique says:

    Hi. Great explanation! However, I have a small question. You wrote:

    "

    Lambdas have access to local variables:

    public static void UseLocal()

    {

       int n;

       Func<int> func = () => { n = 6; return n; };

       n = func();

       Console.WriteLine(n); // Outputs the number 6

    }"

    Now, it might be just me, but you seem to be using n as the variable name both for the function and the lambda.

    { n=6; return n;} I guess that n is local to the lambda, and totally different scope than

    "int n" a bit above? Or is there a chance that the lambda has access to the local vars of the block where it is declared?(you wouldn’t need to reassign it as in n = func() if that was the case?)

    To add to the other posts, I know this is just an example, but using the var n was enough to confuse me a bit and make me need some time to understand, making "maintenace" just that bit more expensive. And I’ve been programming for a few years…

    If LINQ is going to simplify things, and lambdas are the simpler way to do LINQ then by all means use them.

    But sometimes the fact that you can write something in fewer lines does not mean it is going to be easier to maintain. Who was it who said "I would have written you a shorter letter, but I didn’t have the time"?

    Cheers,

    Enrique

  26. Chris says:

    I just wanted to stick my oar in regarding the simple code vs new technology debate. I personally favour keeping code simple and sticking to well-known coding constructs to ensure code remains easily readable and maintainable by a wide variety of developers. I think this is what Ted’s post is getting at. It’s interesting to note that microsoft have given us lambdas yet the code analysis tool they ship with VS 2005 tells us not to use reference and output parameters as they may introduce too much complexity. It’s also interesting to note that they gave us anonymous methods and yet not long after we’re advised not to use them as we’ve now got lambdas!

    In fact, I find anonymous methods to be a happy medium here – they are clearer in syntax than lambdas, and don’t exactly take a lot more work to produce. I think if you showed examples of lambdas and anonymous methods to programmers who weren’t familiar with either, they’d be much more likely to figure out the anonymous methods, and this is the important thing for me.

    But there is a bit of a chicken and egg thing here – if you never use lambda expressions because you think that other programmers may not be familiar with them, then how can you expect anyone to ever become familiar with them? So maybe just start using them, and comment well 🙂

  27. Johnny says:

    Yeah, just what we need. LESS readable code. I would rather have a few more lines and be readable.

    How is Func<int,long,int,string> = f(age,…

    better than (int age, long size…

    The former puts the type right next to the var name, making it much more readable.

  28. Enrique,

    Actually no variables were defined in the scope of that lambda expression.  There’s nothing inside the parens, which is where the local variables are defined for lambdas when they’re set up as delegates.

    Perhaps this would be a better example to illustrate being able to access variables outside of the scope of the lambda expression:

    public void UseLocal()

    {

    int n;

    int[] nums = {0,1,2,3};

    Func<int> func = () => { return nums.Last(); };

    n = func();

    Console.WriteLine("{0}", n);

    }

    However the same could be accomplished by:

    public void UseLocal()

    {

    int[] nums = {0,1,2,3};

    int n = nums.Last();

    Console.WriteLine("{0}", n);

    }

    But lets say you wanted to return the last instance of a number meeting a given criteria.  You could do something like this:

    public void RunSnippet()

    {

    int[] nums = {0,1,2,3};

    int n = nums.Last(item => item < 3 && item > 1);  //Returns 2

    Console.WriteLine("{0}", n);

    }

    It’s a bit overkill for something so simple, but the concept is what’s important.

  29. Enrique says:

    Thanks for that Rich, but my question then is, given the same fragment of code:

    "public static void UseLocal()

    {

      int n;

      Func<int> func = () => { n = 6; return n; };

      n = func();

      Console.WriteLine(n); // Outputs the number 6

    }"

    if n refers to the local(to the normal function) var, what’s the point in returning it and then assigning it? Why not use an action instead:

    "public static void UseLocal()

    {

      int n;

      Action func = () => { n = 6; };

      func();

      Console.WriteLine(n); // Outputs the number 6

    }"

    Perhaps I am missing the point, but what I was trying to say was that using lambdas might be very clever but not necessarily wise, since they can ADD complexity even though they remove lines of code.

     If you look at the examples above(and if I’m right about them!), both FUN and Action can be used, but the example using FUNC was perhaps more appropiate for an Action? If you are introducing tool A do to thing A and tool B to do thing B, but you explain it by using tool A to do thing B, maybe it is not as obvious as it could be?

    Bottom line is, having less lines of code does not necessarily mean having more maintainable code.

    Cheers,

    Enrique

  30. Emre Aydinceren says:

    I don’t understand anonymous method bashing. They are extremely using in writing lean code. You don’t always need resusability.

    I see great value in anoymous methods especially when dealing with event hanlders. For example:

    myButton.Click += { myButton.Enabled=false;}

  31. Steve Cooper says:

    I’ve been getting some big gains with Lambdas with C#3.

    Particularly, algorithmic code — code that does complex operations rather than defining data strucutures — is about 30-50% of it’s equivalent size under C#2. Used right, lambdas make things a great deal clearer.

    The big win is in converting and filtering sequences of data — something you find yourself doing all the time. Being able to write code like the following makes things much shorter than their equivalent. Consider this code, which takes the contents of a source code file and cleans it up into trimmed lines, removing empty lines and line comments;

    return fileContents

     .Split(‘n’)

     .Select(line => line.Replace("r", ""))

     .Select(line => line.Trim())

     .Where(line => line.StartsWith("//") == false);

    The equivalent C#2 is just longer and more involved. The extra code makes it harder to follow what the code is intended to do.

  32. Jeff says:

    Excellent article, good comments too.  Have to say i’m loving working with var and lambda’s with linq, the speed at which i am now producing working performant code has near doubled, and since im maintaining the solution and documenting it i have no qualms over using this new tech, although it took a short while to get used to i feel teaching it to the jr dev’s will not be as hard as teaching them anon delegates….

  33. Todd Hile-Hoffer says:

    I agree with Johnny

    A couple extra lines of code is well worth it when it is easier to read!

    C# 2.0 is great because it is so easy to read, understand and maintain.

    Less isn’t always more. For example, a study just proved that people read real sentences quicker than text messages even though they are twice as long. I find the same to be true with code. Sometimes you can read 4 or 5 lines of code quicker than 1 line.

    These lambdas just make the code harder to read and follow. So what if you can write the code quicker. When you have jump back into a project that you haven’t worked on for months or (that some consultant made a few years ago) this crappy syntax is going to make things more difficult.

  34. Mohammad says:

    Excellent.

    I was the best article about Lambdas that I was reading so far.

Skip to main content