tags:

views:

292

answers:

7

I read an answer to a question on Stack Overflow that contained the following suggested code:

Action<Exception> logAndEat = ex => 
{  
    // Log Error and eat it
};

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

My question is: what is the advantage (if any) of using a lambda expression for LogAndEat as opposed to the (in my view simpler and more obvious) private method as follows:

private void LogAndEat(Exception ex)
{
    // Log Error and eat it
}

Edit: Thanks for the answers so far but just restating my fundamental question a little more clearly: which approach is better/would you recommend in this instance? A lambda expression or a private method?

+8  A: 

Variables captured by logAndEat would otherwise be parameters to the LogAndEat method. You could consider it a form of currying.

Bryan Watts
+1 although that isn't happening in this particular code sample. It's one good reason to do it though.
Matt Hamilton
+1 its all about scope
Darko Z
Is it really a form of currying ?
Int3
Bryan,As my understandings, currying breaks a function/method that takes multiple parameter in such a way that method can be called using a sequence of function with a single argument. Please put some lights on if I am wrong ?
Int3
@Int3: Each captured variable is conceptually a parameter to the method. The closure supplies the reference, so it can be removed from the explicit parameter list; the intent, though, looks very similar to traditional `g(x) = f(x, 2)` currying.
Bryan Watts
OK. I've now read a bit about currying but as the other comments noted it doesn't look like it's happening here (unless logAndEat is calling other methods), so is the only advantage that noted in Matt Hamilton's answer that it is more explicit in the *intended* scope of the expression?
Ben Robbins
@Ben Robbins: The body of `logAndEat` isn't specified, so we don't know that it's not happening. That ambiguity led to my answer. I was looking for an actual semantic difference.
Bryan Watts
@Bryan Thanks for the clarification.
Int3
+11  A: 

I guess you could think of the lambda expression in this example as being a little bit like Pascal's nested functions, in that it's code that can only be executed by the method it's declared in.

A private method could be called from any method in the same class, while a lambda like this is local to the current method and is therefore explicitly only used in that context.

That's really the only advantage I can think of - being explicit in terms of expected usage.

Matt Hamilton
Though of course you *can* pass the delegate out if you want. There is no constraint whatsoever that prevents you from executing the code outside of the declaring method if the delegate instance is passed out.
Eric Lippert
@Eric yeah, you could always return the lambda for sure. Didn't seem to be something the example code was going to do so I discounted that possibility. :)
Matt Hamilton
So does that then counter the thrust of your response, or could one argue (as it seems to me) that your answer is correct if you consider the *intended* scope of the expression, as opposed to the actual possible scope if the delegate instance is passed out? Your answer makes sense to me but using a lambda expression like this just seems a bit *tricky* to me - in that it's not wrong, it's just doing something in an unusual way for marginal benefit.
Ben Robbins
Yeah my argument still holds if you're not returning the lambda from the method (or assigning it to a private field or whatever).
Matt Hamilton
I wrote the code in the original question, and in this case Matt is right about why I wrote it that way. There was nothing to imply that the "log and eat" functionality was reusable (otherwise I assume it would have been a method call in the question) so I just demonstrated one way to encapsulate common code inside the boundaries of a function without leaking any implementation details outside the function. Of course, if the code was useful and reusable then it would make more sense to put it in a function rather than a delegate.
Greg Beech
A: 

IMO I don't like tiny little private functions that are only used in another private method wondering around my classes I just find them ugly, that's why I'd use the lambda in that sample

I don't think there's gonna be a performance impact in using the lambda instead of a function

camilin87
+1  A: 

A lot comes down to personal preference, nobody can say one absolute way is the right way or the wrong way.

Lambda Expressions behave like closures in other languages, the cool thing about them is that they can access variables scoped to the method they're declared in. This adds a lot of flexibility to what you can do in your code, but comes at a cost of not being able to modify code in that method while debugging.

For that reason, if you're going to be logging errors, you might find yourself in a debugger in that method at some time or another. If you use a lambda, you won't be able to modify any code at runtime - so for this reason my preference would be to use a separate private method that accepts the exception as its parameter.

Kevin McKelvin
+3  A: 

LogAndEat can reference private fields within the function where it's defined. So:

private bool caughtException; 

Action<Exception> logAndEat = ex => 
    {  
        caughtException = true;
    };

try
{
    // Call to a WebService
}
catch (SoapException ex)
{
    logAndEat(ex);
}
catch (HttpException ex)
{
    logAndEat(ex);
}
catch (WebException ex)
{
    logAndEat(ex);
}

if (caughtException)
{
    Console.Writeline("Ma, I caught an exception!");
}

This is a trite example (!) but this potentially can be a lot tidier than passing a bunch of parameters through to a private method.

Jeremy McGee
A "private field" in a function is called a variable.
erikkallen
+1  A: 

To understand whether it's better to use a lambda expression (as I did in the original answer) or use a 'proper' method, we need to make a decision based on how reusable the common error handling code is.

  • If the common error handling code is completely reusable by other functions in different classes across the application, then it should probably be an internal or public function, which may be in a different class if that makes the code organisation more sensible.

  • If the common error handling code is reusable by other function in the same class only, then it should probably be a private function in the same class.

  • If the common error handling code is not reusable by any other function, and should only ever be used by this particular function, then you have two choices. The first is to use a delegate to encapsulate it within the boundaries of the function, ensuring that the function does not leak any implementation details. The second is to use a private function in the same class with a comment that it should only be called by the function it is intended for.

In the third case, there is no clear 'best way' to do it as both are perfectly legitimate ways to achieve the same goal. My tendency would be to use a delegate when the common code is small and/or you need some of the behaviour of delegates like capturing variables.

Now, coming back to the question, why I wrote the code using a delegate? I had no information about whether the error handling code was re-usable, so I assumed that it was not, and decided to use a delegate as I figured people would find it easy to go from this to realising it could be a 'proper' method (as you have) whereas if I showed use of a 'proper' function people may not realise that a delegate would be an alternative.

Greg Beech
+1  A: 

Thanks everyone for the great answers which I have up-voted, but I thought I'd summarize them to try and capture the pros and cons in one answer.

Pros of using a lambda expression (LE) instead of a private method:

  • A LE is scoped to the method in which it is declared so if it is only used by that method then that intent is made explicit by a lambda expression (even though it is possible to pass out a delegate to the LE, one can still argue the intent of declaring a LE in a method is that the LE is scoped to the method). That is, being explicit in terms of its expected usage.
  • Lambda expressions behave like closures so they can access variables scoped to the method they are declared in. This can be neater than passing lots of parameters to a private method.
  • Variables captured by a LE would otherwise be parameters to a private method and this can be exploited to allow a form of currying.

Cons of using a lambda expression instead of a private method:

  • Because the LE can access variables scoped to the method in which they are contained, it is not possible to modify code in the calling method while debugging.

There is also the more subjective issue of maintainability and one could argue that LE are not as well understood by most developers as a private method and thus are somewhat less maintainable. One could also argue that a LE improves maintainability because it is encapsulated in the method in which it is called as opposed to a private method which is visible to the entire class.

Ben Robbins