Reputation: 12498
I think I understand how closure is implemented in C# and .NET. When the CLR detects that a function will be passed outside its scope and acts on a free variable, it will package the function and the variable into a custom class.
So how is this different from what happens when an object
calls one of its own functions? The object
itself is passed into the function as the first variable so that if the function needs any of the object's other functions, properties, or fields, it has access to them.
I think I'm missing something here, and would like some sort of explanation of what is going on in both cases: closure, and the case where an object is calling one of its own methods.
Upvotes: 0
Views: 72
Reputation: 25678
Normal method calls on an object has nothing to do with Closures; You only have a closure if you package that method call as a delegate!
In order to understand what's going on you need to have a good grasp on the concept of "value type" and "reference type". Talking about Object
is not explicit enough in .net since Object
is at the bottom of the hierarchy for everything, including value-types (int
is also an Object
). It's much easier to start thinking of method calls on pure reference types, like class instances.
Take your ordinary class variable and instantiation:
List x; // variable declaration
x = new List(); // instantiation
or, on a single line:
List x = new List();
The "body" of your instance will stay in a memory area that's called the Heap. The x
that you're working with only holds a reference to that memory area, and that's why this is called a reference type
.
When you call a method on the List
using the x
variable, the method needs to know on what list to work. So the method simply gets a reference to that body of the instance as the first parameter, the this
parameter. It's incorrect to say the CLR or the Compiler passes "the object" because the object is always on the heap, it only passes a reference (or a pointer).
When the that method needs to call a different method of the same object, it simply passes the same this
as the first parameter, the one it received itself.
A normal method call would look like this:
x.Add(Something); // calls instance method "Add" on "x"
When the compiler sees that it knows the reference to use x
as the this
(the first parameter, the hidden one) for the call to Add
. There's no "closure" in there!
Here's what a closure would look like:
List<int> A = new List<int>();
List<int> B = new List<int>();
Action<int> aDelegate; // <-- declare a delegate type variable
// Action<int> is a delegate that returns void and
// takes a single int parameter.
aDelegate = A.Add; // <-- initialize the delegate using an instance method of object A
aDelegate(7); // <- notice the call! No reference to "A" because "A" is already stored in aDelegate
aDelegate = B.Add;
aDelegate(8); // <- notice the call! No reference to "B" because "B" is already stored in aDelegate
If you look closely at what happens when you call the delegate (aDelegate(7)
), the compiler somehow needs to call the Add
method on object A
, but you can't see that, it's hidden. The delegate encapsulates both the reference to the object A
and the address of the Add
method and that's why it's called a closure
. For contrast look at what happens when you do aDelegate(8)
; This time method Add
is called on object B
, but there's no way to guess that because again, the reference to object B
was buried inside the delegate (the closure).
Upvotes: 1