Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do these two functions not return the same value?

Consider this code snippet and try to guess what y1 and y2 evaluate to

static class Extensions
{
    public static Func<T> AsDelegate<T>(this T value)
    {
        return () => value;
    }
}
class Program
{
    static void Main(string[] args)
    {
        new Program();
    }

    Program()
    {
        double x = Math.PI;

        Func<double> ff = x.AsDelegate();
        Func<double> fg = () => x;

        x = -Math.PI;

        double y1 = ff();  // y1 = 3.141..
        double y2 = fg();  // y2 = -3.141..

    }
}

You might say -Aha- double is a value type and so the value returned by the extension method is a copy of the main x. But when you change the above into delegates of classes the results are still different. Example:

class Foo
{
    public double x;
}
    Program()
    {
        Foo foo = new Foo() { x=1.0 };

        Func<Foo> ff = foo.AsDelegate();
        Func<Foo> fg = () => foo;

        foo = new Foo() { x = -1.0 };

        double y1 = ff().x;    // y1 = 1.0
        double y2 = fg().x;    // y2 = -1.0
    }

So the two functions must return two different instances of the same class. It is interesting to consider that ff() carries with it a reference to local variable foo, but fg() does not and it relies on what is in scope currently.

So what happens when these two delegates are passed on to other parts of the code which do not have visibility to foo instance? Somehow the question of who owns what information (data) is becoming less and less clear when extension methods are combined with delegates.

like image 591
John Alexiou Avatar asked Nov 09 '10 17:11

John Alexiou


People also ask

Why my function does not return value?

Void functions are created and used just like value-returning functions except they do not return a value after the function executes. In lieu of a data type, void functions use the keyword "void." A void function performs a task, and then control returns back to the caller--but, it does not return a value.

What does it mean to not return a value?

Function with no argument and no return value: When a function has no arguments, it does not receive any data from the calling function. Similarly, when it does not return a value, the calling function does not receive any data from the called function.


2 Answers

AsDelegate captures the variable value (the parameter of AsDelegate), while () => x captures the variable x. So if you change the value of x, the lambda expression will return a different value. Changing x doesn't change value though.

See: Outer Variable Trap

like image 145
dtb Avatar answered Sep 22 '22 02:09

dtb


In AsDelegate, we are capturing the the argument "value". the value of this argement is taken as a copy of the value of the variable at the time the method is invoked, and never changes - so we see the original object.

The direct lambda captures the variable foo (not the value of the variable - the variable itself) - thus we do see changes to this.

Basically adding a method call changed the thigh being captured.

like image 34
Marc Gravell Avatar answered Sep 23 '22 02:09

Marc Gravell