3

Possible Duplicate:
Detailed Explanation of Variable Capture in Closures

public class Polynom {
    public delegate double Func(double x);
    private Func f;
    public Polynom(params double[] coef) {
        f = (double x) => {
        double sum = 0;
        for ( int i = 0 ; i < coef.Length ; i++ )
            sum += coef[i] * Math.Pow(x,coef.Length-1-i);
        return sum;
        };
    }
    public double evaluate(double x) {
        return f(x);
    }
    public static void Main() {
        Polynom a=new Polynom(1,1,1);
        Polynom b=new Polynom(2 , 2 , 0);
        Console.WriteLine(a.evaluate(2));
        Console.WriteLine(b.evaluate(2));
        Console.ReadKey();
    }
}

Notice how the code in f uses coef, while coef is a paramater of the constructor. if you think about it, that should not work unless it gets a ref copy of coef, because once the constructor done its job, its parameters are suppose to vanish. but somehow, calling f manages to use coef as if it still exists. HOW?

I would love a good deep explantion if someone can explain this...

Another thing that i would like to know is, the code is the same on every Polynom instance, but does every instance get another copy of that same code? if so, is there a way to make my class run with just 1 copy of that code? (like make it static somehow)

Community
  • 1
  • 1
Ofek Ron
  • 8,354
  • 13
  • 55
  • 103
  • This has been asked many times before. – Kendall Frey Jul 14 '12 at 14:42
  • Has it been? so whats the answer then? – Ofek Ron Jul 14 '12 at 14:44
  • Here's a question which asks it at the next step: http://stackoverflow.com/questions/6013094/why-does-code-generate-msil-class-called-c-displayclass1 Your next step should be to either load your assembly in JustDecompile or ildasm and see how the compiler is creating the code the represent your lambda expression. – Joseph Yaduvanshi Jul 14 '12 at 14:48

2 Answers2

2

The function is a so-called closure, which is well-explained in this wikipedia article

A closure allows a function to access variables outside its immediate lexical scope. An upvalue is a free variable that has been bound (closed over) with a closure. The closure is said to "close over" its upvalues. The referencing environment binds the nonlocal names to the corresponding variables in scope at the time the closure is created, additionally extending their lifetime to at least as long as the lifetime of the closure itself. When the closure is entered at a later time, possibly from a different scope, the function is executed with its non-local variables referring to the ones captured by the closure.

Concerning your second question: Making a closure static would somewhat contradict the purpose of functional principles.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
2

Lambdas and other delegates are implemented as closures, special objects created by the compiler that combine a method of your lambda with all the data that the lambda needs to complete its execution. The values of all local variables and parameters that are used inside the lambda are implicitly captured as data members of the closure, so they remain available until the lambda itself is no longer referenced.

You can think of the closure as a special anonymous class created specifically for your lambda. In your case, a closure may look like this:

private Polynom_Closure {
    private readonly double[] coef;
    public Polynom_Closure(double[] coef) {
        this.coef = coef;
    }
    public double evaluate(double x) {
        double sum = 0;
        for ( int i = 0 ; i < coef.Length ; i++ )
            sum += coef[i] * Math.Pow(x,coef.Length-1-i);
        return sum;
    }
}

The compiler makes this class invisibly for you, and then inserts its use into your code:

public Polynom(params double[] coef) {
    f = new Polynom_Closure(coef).evaluate;
}
Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523