5


In C#, lambda can access local variable, and also return some data.

then, which is better in following situation?

int num;
Func<int> func = ()=>{return 10;}
num = func();

vs

int num;
Action action = ()=>{num = 10;}

I think, the performance is different. Which is better?



UPDATE(I dont know how to use StackOverflow)

My code here.

ErrorCode errorCode;
errorCode = DatabaseUtility.Read<ErrorCode>(
    conn,
    DatabaseUtility.CreateSelectQuery(....),
    reader =>
    {
        if(reader.Read())
            return ErrorCode.None;

        return ErrorCode.InvalidParam;
    });

But in this case, may be I can do like this.

ErrorCode errorCode;
DatabaseUtility.Read(
    conn,
    DatabaseUtility.CreateSelectQuery(....),
    reader =>
    {
        if(reader.Read())
            errorCode = ErrorCode.None;
        else
            errorCode = ErrorCode.InvalidParam;
    });

And, this is the method definition.

public static class DatabaseUtility
{
    public static Read<T>(
        MySqlConnection conn,
        string query,
        Func<MySqlDataReader, T> callback);
}
9
  • 1
    what are you trying to achieve? what do you mean by better ? what is stopping you from just assigning 10 to num directly? Commented Mar 8, 2015 at 14:10
  • @Selman22 what are you asking? it's just simple example. If you want to know why I want to know this knowledge, then I can tell you. I try SELECT some data from my DB, and handle the data. For it, I define utility method with Func type parameter. And I handle my data after the utility method, so the Func return my data. but lambda can access local variable, why i return my data? I can assign my data into my local variable. isn't it? so I ask, which is better code. Commented Mar 8, 2015 at 14:15
  • What makes you think performance is different ? Is your app so perfect that you have to bother on such micro optimization ? Commented Mar 8, 2015 at 14:15
  • 1
    @WonHyoungLee These two functions do completely different things, so you're comparing apples and oranges here. Performance isn't really the primary issue. Without a concrete example of how you would use them, it's close to impossible to answer your question. Commented Mar 8, 2015 at 14:19
  • 1
    lambada - the forbidden code... =] Commented Mar 8, 2015 at 14:26

4 Answers 4

4

Gibbo is right: returning the value is clearer, so you should use that and not worry about performance, unless this code is in the 3% of code when microoptimizations make sense.

But returning the can also be more efficient, because it doesn't require heap allocation for the closure object and because it means num is going to be compiled as a local variable, not a field on the closure object (accessing local variables is cheaper than fields).

Also, if you're going to return the value, there is no reason to declare the variable so early, which will make your code slightly shorter:

Func<int> func = ()=>{return 10;}
int num = func();
Sign up to request clarification or add additional context in comments.

3 Comments

if I use a local variable in lambda, the variable has been changed like member variable? My updated code is no different? If i use same code more than once, the lambda return data each time, isn't it? but if I access same local variable(may be changed field), the only one field is there. which one show me better performance? I know it's very very very small difference. I just wonder it.
Yes, with your updated code, it's still the same. And if you use the same more than once, it's also still the same: creating the closure object and accessing a field is going to be more expensive than not creating the object and accessing a local variable.
If i create on lambda and call it, the closure object is created each time? if not, the return cost of each called time is more expensive than created closure object, isn't it? then, Can I understand that the closure object is created every time when i call func() again?
2

The first one is better designed. It is reusable and can be called again and again on different variables (if required).

Performance I am not sure of, most likely negligible.

1 Comment

+1 for the reusability. IMHO a well written software is worth way more than a bit more performing block. In your code you deal with DB, which typically takes a lot longer than some C# operations. 100% vote for anything is easy to read, maintain and possibly follows the GOF patterns: en.wikipedia.org/wiki/Design_Patterns
1

Actually there is a big semantical difference.

() => 10;
() => x = 10;

Both return 10. The difference is that in second case, the x variable is captured, bound to the lamba body, and can travel through contexts.

Imagine:

void SomeFunction()
{
    int variable;
    Execute((a) => variable = a);
}

void Execute(Action<int> statement)
{
    statement.Invoke(7);
}

Here SomeFunc has no idea what the value of variable will be when exiting the function context. On the other hand the Execute has no idea what will happen with the value passed into the function object through Invoke. This could be useful in some encapsulation contexts. Or possibly in situations where you hit C#'s generics limits (which is very easy by the way).

You can then think both ways when it comes to your code. e.g. "Do I want to handle the errors on my side, or do I provide the user of my interface with means of error handling?"

But then, I'd rather use abstract class to implement/enforce the aforementioned behaviour instead of lambdas.

Generally speaking, sending captured variables over contexts seems to hide dependencies and makes your code harder (in some cases maybe even impossible) to read and debug. I think it should only be used in scenarios where all other means of C# either yield very slow or very ugly code.

4 Comments

There is no fact what i wander exactly. And I don't know your point since my English is bad. you mean do not use lambda?
No, use lambda. But avoid using captured variables unless necessary or trivial.
captured variables mean local variables of outside of lambda?
yes, captured variables are the ones declared outside of lambda body and used inside. In that case, lamba is called a closure over those variables.
1

I want to raise a small issue with the code you posted:

public static class DatabaseUtility
{
    public static Read<T>(
        MySqlConnection conn,
        string query,
        Func<MySqlDataReader, T> callback);
}

the method has no return type signature! is it void? If it is void the code you posted won't work:

ErrorCode errorCode;
errorCode = DatabaseUtility.Read<ErrorCode>(
    conn,
    DatabaseUtility.CreateSelectQuery(....),
    reader =>
    {
        if(reader.Read())
            return ErrorCode.None;

        return ErrorCode.InvalidParam;
    });

if it is T already then there is no need to declare a Func to pass to the function Read.

I think in this very case return value of the function Read should be T, and given that you want to perform an action with the datatype you are retrieving (in case of some error or for some other case) it would be better off to pass an action instead:

public static class DatabaseUtility
{
    public static T Read<T>(
        MySqlConnection conn,
        string query,
        Action<MySqlDataReader> callback);
}

Premise that performance wise it should not be a problem unless you are targeting a real time application (which I think it's not your case). However that would be the neater solution IMHO.

hope it helps.

1 Comment

missing return type at my post is my mistake. Alos Read<T> method includes return callback(MySqlDataReaderInstance);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.