Linked by Eugenia Loli on Sun 30th Oct 2005 20:01 UTC
.NET (dotGNU too) While demonstrating the rudiments of anonymous methods, Paul Kimmel answers the question "Are anonymous methods just someone being a bit too clever?"
Thread beginning with comment 53318
To read all comments associated with this story, please click here.
.Net and capturing local variables.
by steveftoth on Sun 30th Oct 2005 22:09 UTC
steveftoth
Member since:
2005-10-30

RE: the serverside article, a very good read.

Re anonymous functions and capturing local variables...
Wow that seems like an easy to misunderstand 'feature'. It seems to me that the rules are not well defined on how local variables are captured in to anonymous delegates. Is there a reference? Why do they get promoted to some special semi-real variables instead of something 'simple' that won't get abused. I'm a java person so I'm biased, but I find that the enforcement that local variables cannot migrate to anonymous inner class definitions without being declared final is a good one since it makes debuggin easier, easier to read code and makes it 'more' deterministic rather then his own example where you're not sure what will happen due to thread inconsistincy.

Reply Score: 2

rayiner Member since:
2005-07-06

The rules seem well-defined enough to me. I think the article's focus on the generated code somewhat confuses the underlying simplicity of the mechanism. It helps to think of closures as just being objects, with a single method created at runtime. When a function may create a closure, it's stack frame is allocated on the heap. Any created closures retain a pointer to that stack frame --- it is this stack frame that comprises the "member data" of the closure. Therefore, two closures created by the same function on different invocations will refer to two different stack frames, while two closures created by the same function on a single invocation will refer to the same stack frame.

Reply Parent Score: 2

japail Member since:
2005-06-30

Do you really think that this description simplifies the matter at hand, since you use terms like 'stack frame,' 'pointer,' 'heap' and so forth?

These are essentially lexical closures and could be understood abstractly in terms of capturing the enclosing lexical environment, which means that free variables in a method body will be substituted from the calling environment at runtime. That's it. It's not especially complicated. All they have to do is think of a lexical closure capturing free variables from the environment similarly as they might think of free variables (fields, for example) in a method body being obtained from the implicit receiver at method invocation.

class X
int z
public int Foo(int y) { return y + z }
public X(int s, int r) { z = s * r }

e1 = X(1, 2)
e1.Foo(1)
e2 = X(2, 3)
e2.Foo(1)

Here z is substituted with e1.z and e2.z respetively in the method when Foo is invoked.

public delegate int FooFN(int y)

public FooFN MkFoo(int s, int r) {
return delegate(int y) { return s * r + y }
}

FooFN Foo1 = MkFoo(1, 2)
FooFN Foo2 = MkFoo(2, 3)

Foo1(1)
Foo2(1)

Here s and r are substituted by 1 and 2 in Foo1 and 2 and 3 in Foo2. This isn't all that hard to understand, and isn't bogged down by any implementation details like what sort of activation records one has.

Reply Parent Score: 2

tummy Member since:
2005-09-14


I'm a java person so I'm biased, but I find that the enforcement that local variables cannot migrate to anonymous inner class definitions without being declared final is a good one since it makes debuggin easier, easier to read code and makes it 'more' deterministic rather then his own example where you're not sure what will happen due to thread inconsistincy.


But then you lose all the power of closures. The ability or the anonymous method to not only access, but mutate the local variables is very important. I use closures *all the time* in C# now that it has it and it has greatly increased code reuse (how can passing around closures/bits-of-code-with-context not?).

Thread safety is no more an issue with closures than with anything else you write. Java only avoids thread safety issues for some uses of closures by simply NOT supportig closures and not allowing you to write your code in that simple manner. If you try to emulate closures with Java and pass the closure to multiple threads, you will get into the exact same problems.

Reply Parent Score: 2

japail Member since:
2005-06-30

I recall Guy Steele saying that inner classes in Java originally permitted mutability, and that they scrapped them because people complained about the automatic heap allocation necessary for implementation.

It's not a matter of "non-determinism." Accessing a field without synchronization from multiple threads is fundamentally no different than accessing a captured variable from a closure with multiple threads without synchronization.

Reply Parent Score: 1