Closure is a first class function that is bound to the environment where it is declared.It means we can assign this function to a variable and pass it around and invoke it.Here is an example -
Func myTestFunc = delegate(string variable1)
{
return "some value";
};
Or using lambda -
Func myTestFunc = variable1 => "some value";
The above function can be assigned to any variable like this -
string myVar = myTestFunc("something");
Lets take some more example and try to analyze the output to understand how closures work.
var myVar = "external Variable";
Func myFunc = delegate(string var1)
{
return var1 + myVar;
};
In the above example the myVar is called as "FreeVariable". A free variable is a variable which is referenced in a function which is not a parameter of the function or a local variable of the function.
What will be the output of this function -
Lets try to calculate it. in "incrementsFunc" i get the function pointer(i used the pointer word here because it helps to visualize it), now i execute this function with input as 5. so my first calculation says
myVar = 1 + 1 -> 2
var1 + myVar -> 5 + 2 ->7
Now i execute same function with input param as 6. Again the calculation will be -
myVar = 1+1 ->2
and var1+myVar -> 6 + 2 -> 8
So i think the answer should be 7 and 8.
What your calculation is? lets see that is there at output-
Its 7 and 9 ------------------------??? How??
Although myVar is a local variable and is suppose to get flushed out after first call, but still its value was there and caused the result to be 9(6 + 3). Well this is called as free variable in lexical environment.
I think we still didnt get the answer of how?. So actually here is what has happened -
The C# compiler detects when a delegate forms a closure which is passed out of the current scope and it promotes the delegate, and the associated local variables into a compiler generated class. It means the local variables are promoted to heap from stack(without boxing), which explains why the value intact. Making this delegate a class, makes it very easy to pass the function around and make an assignment,invoke it. Each time we invoke the delegate we are actually calling the method on this class and as the variables are on heap the values is actually availble. Once we are no longer holding a reference to this delegate, garbage collector will play its role.
So that is all about the concept of closure. lets try some exercise to see if we understand it correctly.
1) what will be the output of following -
delegate void Action();
static void Main(string[] args)
{
int x = 0;
Action a = delegate { Console.WriteLine(x); };
a();
}
Ans - 0
2)
delegate void Action();
static void Main(string[] args)
{
int x = 0;
Action a = delegate { Console.WriteLine(x); };
x =1;
a();
}
Ans - 1. closure bound to its parenting method body and the local variables in it, thus making any change in x will reflect in this function.
3) What will be the output?
public delegate T Iterator() where T : class;
public static Iterator CreateIterator(IList x) where T : class
{
var i = 0;
return delegate { return (i < x.Count) ? x[i++] : null; };
}
static void Main()
{
var iterator = CreateIterator(new string[3] { "string1", "string2", "string3" });
Console.WriteLine(iterator());
Console.WriteLine(iterator());
Console.WriteLine(iterator());
Console.WriteLine(iterator());
}
Ans-
string1
string2
string3
null
Func
{
return "some value";
};
Or using lambda -
Func
The above function can be assigned to any variable like this -
string myVar = myTestFunc("something");
Lets take some more example and try to analyze the output to understand how closures work.
var myVar = "external Variable";
Func
{
return var1 + myVar;
};
In the above example the myVar is called as "FreeVariable". A free variable is a variable which is referenced in a function which is not a parameter of the function or a local variable of the function.
What will be the output of this function -
myVar = 1 + 1 -> 2
var1 + myVar -> 5 + 2 ->7
Now i execute same function with input param as 6. Again the calculation will be -
myVar = 1+1 ->2
and var1+myVar -> 6 + 2 -> 8
So i think the answer should be 7 and 8.
What your calculation is? lets see that is there at output-
Its 7 and 9 ------------------------??? How??
Although myVar is a local variable and is suppose to get flushed out after first call, but still its value was there and caused the result to be 9(6 + 3). Well this is called as free variable in lexical environment.
I think we still didnt get the answer of how?. So actually here is what has happened -
The C# compiler detects when a delegate forms a closure which is passed out of the current scope and it promotes the delegate, and the associated local variables into a compiler generated class. It means the local variables are promoted to heap from stack(without boxing), which explains why the value intact. Making this delegate a class, makes it very easy to pass the function around and make an assignment,invoke it. Each time we invoke the delegate we are actually calling the method on this class and as the variables are on heap the values is actually availble. Once we are no longer holding a reference to this delegate, garbage collector will play its role.
So that is all about the concept of closure. lets try some exercise to see if we understand it correctly.
static void Main(string[] args)
{
int x = 0;
Action a = delegate { Console.WriteLine(x); };
a();
}
delegate void Action();
static void Main(string[] args)
{
int x = 0;
Action a = delegate { Console.WriteLine(x); };
x =1;
a();
}
public static Iterator
{
var i = 0;
return delegate { return (i < x.Count) ? x[i++] : null; };
}
static void Main()
{
var iterator = CreateIterator(new string[3] { "string1", "string2", "string3" });
Console.WriteLine(iterator());
Console.WriteLine(iterator());
Console.WriteLine(iterator());
Console.WriteLine(iterator());
}
No comments:
Post a Comment