Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When not to use lambda expressions [closed]

A lot of questions are being answered on Stack Overflow, with members specifying how to solve these real world/time problems using lambda expressions.

Are we overusing it, and are we considering the performance impact of using lambda expressions?

I found a few articles that explores the performance impact of lambda vs anonymous delegates vs for/foreach loops with different results

  1. Anonymous Delegates vs Lambda Expressions vs Function Calls Performance
  2. Performance of foreach vs. List.ForEach
  3. .NET/C# Loop Performance Test (FOR, FOREACH, LINQ, & Lambda).
  4. DataTable.Select is faster than LINQ

What should be the evaluation criteria when choosing the appropriate solution? Except for the obvious reason that it's more concise code and readable when using lambda.

like image 657
Binoj Antony Avatar asked Mar 23 '09 10:03

Binoj Antony


People also ask

What is a closed lambda expression?

A lambda expression is an anonymous function and can be defined as a parameter. The Closures are like code fragments or code blocks that can be used without being a method or a class. It means that Closures can access variables not defined in its parameter list and also assign it to a variable.

Why a lambda expression forms a closure?

a function that can be treated as an object is just a delegate. What makes a lambda a closure is that it captures its outer variables. lambda expressions converted to expression trees also have closure semantics, interestingly enough.

Are closures lambda functions?

Lambda functions may be implemented as closures, but they are not closures themselves. This really depends on the context in which you use your application and the environment. When you are creating a lambda function that uses non-local variables, it must be implemented as a closure.

What are the disadvantages of lambda expression?

The big paradox of lambdas is that they are so syntactically simple to write and so tough to understand if you're not used to them. So if you have to quickly determine what the code is doing, the abstraction brought in by lambdas, even as it simplifies the Java syntax, will be hard to understand quickly and easily.


1 Answers

Even though I will focus on point one, I begin by giving my 2 cents on the whole issue of performance. Unless differences are big or usage is intensive, usually I don't bother about microseconds that when added don't amount to any visible difference to the user. I emphasize that I only don't care when considering non-intensive called methods. Where I do have special performance considerations is on the way I design the application itself. I care about caching, about the use of threads, about clever ways to call methods (whether to make several calls or to try to make only one call), whether to pool connections or not, etc., etc. In fact I usually don't focus on raw performance, but on scalibility. I don't care if it runs better by a tiny slice of a nanosecond for a single user, but I care a lot to have the ability to load the system with big amounts of simultaneous users without noticing the impact.

Having said that, here goes my opinion about point 1. I love anonymous methods. They give me great flexibility and code elegance. The other great feature about anonymous methods is that they allow me to directly use local variables from the container method (from a C# perspective, not from an IL perspective, of course). They spare me loads of code oftentimes. When do I use anonymous methods? Evey single time the piece of code I need isn't needed elsewhere. If it is used in two different places, I don't like copy-paste as a reuse technique, so I'll use a plain ol' delegate. So, just like shoosh answered, it isn't good to have code duplication. In theory there are no performance differences as anonyms are C# tricks, not IL stuff.

Most of what I think about anonymous methods applies to lambda expressions, as the latter can be used as a compact syntax to represent anonymous methods. Let's assume the following method:

public static void DoSomethingMethod(string[] names, Func<string, bool> myExpression) {     Console.WriteLine("Lambda used to represent an anonymous method");     foreach (var item in names)     {         if (myExpression(item))             Console.WriteLine("Found {0}", item);     } } 

It receives an array of strings and for each one of them, it will call the method passed to it. If that method returns true, it will say "Found...". You can call this method the following way:

string[] names = {"Alice", "Bob", "Charles"}; DoSomethingMethod(names, delegate(string p) { return p == "Alice"; }); 

But, you can also call it the following way:

DoSomethingMethod(names, p => p == "Alice"); 

There is no difference in IL between the both, being that the one using the Lambda expression is much more readable. Once again, there is no performance impact as these are all C# compiler tricks (not JIT compiler tricks). Just as I didn't feel we are overusing anonymous methods, I don't feel we are overusing Lambda expressions to represent anonymous methods. Of course, the same logic applies to repeated code: Don't do lambdas, use regular delegates. There are other restrictions leading you back to anonymous methods or plain delegates, like out or ref argument passing.

The other nice things about Lambda expressions is that the exact same syntax doesn't need to represent an anonymous method. Lambda expressions can also represent... you guessed, expressions. Take the following example:

public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression<Func<string, bool>> myExpression) {     Console.WriteLine("Lambda used to represent an expression");     BinaryExpression bExpr = myExpression.Body as BinaryExpression;     if (bExpr == null)         return;     Console.WriteLine("It is a binary expression");     Console.WriteLine("The node type is {0}", bExpr.NodeType.ToString());     Console.WriteLine("The left side is {0}", bExpr.Left.NodeType.ToString());     Console.WriteLine("The right side is {0}", bExpr.Right.NodeType.ToString());     if (bExpr.Right.NodeType == ExpressionType.Constant)     {         ConstantExpression right = (ConstantExpression)bExpr.Right;         Console.WriteLine("The value of the right side is {0}", right.Value.ToString());     }  } 

Notice the slightly different signature. The second parameter receives an expression and not a delegate. The way to call this method would be:

DoSomethingExpression(names, p => p == "Alice"); 

Which is exactly the same as the call we made when creating an anonymous method with a lambda. The difference here is that we are not creating an anonymous method, but creating an expression tree. It is due to these expression trees that we can then translate lambda expressions to SQL, which is what Linq 2 SQL does, for instance, instead of executing stuff in the engine for each clause like the Where, the Select, etc. The nice thing is that the calling syntax is the same whether you're creating an anonymous method or sending an expression.

like image 183
Rui Craveiro Avatar answered Oct 12 '22 06:10

Rui Craveiro