views:

556

answers:

8

Hi everybody :)

I often find myself using lambdas as some sort of "local functions" to make my life easier with repetetive operations like those:

Func<string, string> GetText = (resource) => this.resourceManager.GetString(resource);
Func<float, object, string> FormatF1 = (f, o) => String.Format("{0:F1} {1}", f, o);
Func<float, object, string> FormatF2 = (f, o) => String.Format("{0:F2} {1}", f, o);

Instead of writing the String.Format-thing over and over, I can happily blow away with FormatF2 e.g. and save myself time and when I need to change something about the formatting, only one place to make edits. Especially when I need the functionality in the given function exclusively, I'm very reluctant to turn them into a real function. While the lambdas above were relatively small... sometimes I have larger ones like (the following is supposed to add data to a table for print output):

Action<string, string, string> AddSurfaceData = (resource, col, unit) => {
    renderTable.Cells[tableRowIndex, 0].Text = "\t" + this.GetText(resource);
    renderTable.Cells[tableRowIndex, 1].Text = FormatF2(paraHydReader.GetFloat(paraHydReader.GetOrdinal(col)), "");
    renderTable.Cells[tableRowIndex, 1].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Right;
    renderTable.Cells[tableRowIndex, 2].Text = " " + this.GetText(unit);
    renderTable.Cells[tableRowIndex, 2].Style.TextAlignHorz = C1.C1Preview.AlignHorzEnum.Left;
    ++tableRowIndex;
};

Again, I need this often and all the benefits of above apply, too. However, as you can see, this one is quite long for a lambda expression.. the question is: When do you draw the line? Is my last lambda too much? What other ways (other than using real functions or trying to stuff the data in containers and loop over them) exist to avoid writing the same code over and over again?

Thanks in advance

Christian

A: 

I personally think its not in good taste to use lambda functions when there is no need for it. I personally wont use a lambda function to replace a simple few lines of procedural code. Lambda functions offer many enhancements, but make the code slightly more complicated to read.

I wouldnt use it to replace string.format.

Andrew Keith
If it is a complex `string.format` that is used many times in the same function, it makes perfect sense to use it. The question is really when the function gets so complicated that it is better to pull it out as a separate private method in your class.
awe
+9  A: 

It is something you use potentially many times within a method, and only that inside that method. I like this idea. Do it if it doesn't make your code hard to read. I would say that you should reconsider if you find it difficult to see what is the content of the lambda function vs. what is the real content of the method. In that case it might be cleaner to pull it out in a separate private method.

At the end, this is really a matter of taste...

awe
+1  A: 

I like the idea. I don't see a better way to maintain code locality without violating the DRY principle. And I think it's only harder to read if you're not accustomed to lambdas.

nikie
+1  A: 

+1 on nikie re DRY being good in general.

I wouldnt use PascalCase naming for them though.

Be careful though - in most cases the stuff you have in there is just an Extract Method in a dress or a potential helper or extension function. e.g., GetText is a Method and FormatF* is probably a helper method...

Ruben Bartelink
+5  A: 

I agree with awe: for small scale reuse inside a method (or even a class) this is perfect. Like the string.Format examples. I use this quite often. It's basically the same thing as using a local variable for an intermediate value that you use more than once, but for code.

Your second example seems to be pushing it a bit. Somehow this gives me the feeling a private method AddSurfaceData (possibly static, depending on its use?) would be a better a fit. That is of course outside of the context that you have, so use your own good judgement.

peSHIr
Making the method static or not depends on the use - If it uses member variables, it is no point in forcing to pass as parameters to the function.
awe
+3  A: 

A Lambda method is an anonymous method.

This means that you should not give it a name.

If you are doing that, (in your case, you are assigning a name with your reference), it's just another way to declare a function.

C# has already got a way to declare functions, and it's not the lambda way, which was added uniquely to pass functions via parameters and returns them as return values.

Think, as an example, in javascript:

function f(var1,var2,...,varX)
{
    some code
}

or

var f = function() {
    some code    
}

Different syntax (almost) same thing.

For more information on why it's not the same thing: Javascript: var functionName = function() {} vs function functionName() {}

Another example: in Haskell You can define two functions:

 function1 :: Int -> Int
 function1 x = x + 2

or

 function2 :: Int -> Int
 function2 = \x -> x + 2

Same thing (this time I think it's the very same), different syntax. I prefer the first one, it's more clear.

C# 3.5, as Javascript, has got a lot of functional influences. Some of them should it be used wisely, IMHO.

Someone said local lambda functions with assignment in a reference is a good substitute for a method defined within another method, similar to a "let", or a "where" clause in Haskell.

I say "similar" because the twos have very different semantics, for instance, in Haskell I can use function name which is not declared yet and define it later with "where", while in C#, with function/reference assignment I can't do this.

By the way I think it's a good idea, I'm not banning this use of lambda function, I just want to make people think about it. Every language has got his abstraction mechanism, use it wisely.

volothamp
I know Haskell and ever since I learned it, my C# programming has gotten more "functional", so I'm aware that I "somewhat" abuse the basic idea of Lambdas being anonymous functions.. but it's very tempting to do so ;)And hey, in C++ we abuse templates to calculate fibonacci sequences etc :)
Christian
I think naming a functional block for repeated use inside a method shouldn't be banned for the sake of respecting a general principle (lambda methods are anonymous methods).
Sorin Comanescu
There is nothing that says a lambda must be "anonymous"... However C#3 lacks the ability to declare inner functions (which is a shame); in the code above, while GetText, FormatF1 and FormatF2 could be unrolled to proper [static] methods (although that might be misleading about their scope!) it is unspecified if a "closure semantics" are needed in the last example.
pst
The difference to Haskell is that Haskell allows local function definitions inside a function through let. C# lacks local function definitions, but I think named lambdas are a good substitute for that.
nikie
+1  A: 

I have no problem with the long example. I see that you are repackaging compound data very elegantly.

It's the short ones that will drive your colleagues to investigate the advantages of voluntary institutionalization. Please declare some kind of constant to hold your format string and use "that String.Format-thing over and over". As a C# programmer, I know what that does without looking elsewhere for home-spun functions. That way, when I need to know what the formatted string will look like, I can just examine the constant.

Wade
A: 

I agree with volothamp in general, but in addition ...

Think of the other people that have to maintain your code. I think this is easier to understand than your first example and still offers the maintenance benefits you mention:

String.Format(this.resourceManager.GetString("BasicFormat"), f, o);
String.Format(this.resourceManager.GetString("AdvancedFormat"), f, o);

And your second example appears to be just a different way to declare a function. I don't see any useful benefit over declaring a helper method. And declaring a helper method will be more understandable to the majority of coders.

Lee