Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When are properties in closures evaluated?

Several methods in our code base use a 'MaybeObject' that can be passed into functions when a result might be known, or might rely on an external webservice call that has not yet been carried out. For example, the property below can either have a specified known value, or if not specified and called after the async call is complete it will return the result of the Async call.

private string _internalString;
public string stringProp
{ 
    get
    {
        if (!string.IsNullOrEmpty(_internalString))
            return _internalString;
        return resultOfAsyncCallFromSomewhereElse;
    }

    set { _internalString = value; }
}

Obviously, trying to reference the property before the async call is complete would cause a null reference exception so we also have a flag to check if the value is available.

The question is, in the code below would the creation of the lambda try and evaluate stringProp (which might not be populated yet), or would evaluation be deferred until the resulting Action is called (which would be after checking the async operation is complete)?

public Action ExampleMethod(MaybeObject maybe)
{
    return () => doSomethingWithString(maybe.stringProp);
}
like image 724
mavnn Avatar asked Nov 28 '11 11:11

mavnn


2 Answers

In C# all would be evaluated whilst execution since C# lambda Closures is not a true Closure which able to resolve a state of captured environment in moment of creation.

() => doSomethingWithString(maybe.stringProp);

Here is even reference maybe could be null and you won't got any issues like NullReferenceException until executing a delegate. This trick sometimes used for late-bound value resolving.

Wikipedia: Closure:

A closure retains a reference to the environment at the time it was created (for example, to the current value of a local variable in the enclosing scope) while a generic anonymous function need not do this.

Nice overview of C# Closure specifics - Anonymous methods and closures in C#

From the definition of Closure it can be inferred that Closure remembers the values of the variables during its creation. However in C# the outer local variable (i in this case) is shared with the anonymous method by creating it on the heap. This means any change to it in the anonymous method changes the original value and when the method is called the second time it gets the modified value of i as 1 (see second line of output). This leads many to argue that anonymous method is not actually a Closure as by its definition the value of a variable at the time of creation of the Closure should be remembered and not modifiable.

like image 62
sll Avatar answered Sep 29 '22 22:09

sll


Evaluation will be deferred until the resulting Action is called.

The code referenced by a delegate is only executed when the delegate itself is explicitly invoked, regardless of how the delegate itself was created.

For example, these ways of passing the code to execute through the Action delegate are all equivalent, and the doSomethingWithString method won't be executed until a call to Action() is made:

Explicit method (.NET 1.1):

private MaybeObject maybe;

public Action ExampleMethod()
{
    return new Action(DoSomethingWithMaybeObject);
}

private void DoSomethingWithMaybeObject()
{
    doSomethingWithString(maybe.stringProp)
}

Anonymous method (.NET 2.0):

public Action ExampleMethod(MaybeObject maybe)
{
    return delegate() { doSomethingWithString(maybe.stringProp) };
}

Lambda (.NET 3.5):

public Action ExampleMethod(MaybeObject maybe)
{
    return () => doSomethingWithString(maybe.stringProp);
}

See also:

  • Delegates
  • Anonymous Methods
  • Lambda Expressions
like image 35
Enrico Campidoglio Avatar answered Sep 29 '22 22:09

Enrico Campidoglio