November 09, 2001
Pavel \"EvilOne\" Minayev wrote:
> 
> <la7y6nvo@shamko.com> wrote in message news:s7csnbpsmx5.fsf@michael.shamko.com...
> 
> > Only the heap-allocated locals that are referenced by a closure
> > that is still accessible need be kept.  Any others would be
> > cleaned up just like any other unreachable object.  Also any
> > local variables _not_ referenced by closures can be allocated on
> > the stack and pruned in the usual way.  No stack frames need
> > be kept.
> 
> Does this mean that all locals that are referenced by a closure
> automatically become static (since their only instance reside on heap)?
> Or will there be a separate stack for them (again, on heap)?

They would be in the heap I would presume.  Once the instance of the
closure the references them goes away (is no longer referenced itself)
these variables would be disposed of by GC.  The variable could probably
be allocated and deallocated as a group.

> BTW another problem: compiler can't always be sure that closure gets returned from the function on a specific call - if, for example, it's in conditional statement. If closure references, say, a local string, and function is called several times, but actually returns closure only once, all instances of that local string are preserved till the end of the program...

No.  The closure is effectively a reference to a chunk of code and the chunk of data.  When all references to it go away, the chunk of data (and all references to said string) are destroyed by the GC.  It really isn't that complex to follow.  The complex part would be how the compiler decides what goes on the stack (not referenced by any closure) what goes into heap allocated closure blocks.  I bet this could get harry if you declare several different closures in a given scope.

	int f(){
		int a, b, c;
		int F1() = []{print (a, b);};
		while(elsewhere()){
			int a, d;
			F1 = [] {print(a, b, d);
		}
		int d;
		F1 = []{print(a, b, d);
	}

The easy way would be to allocate each shared variable separately, but that could be very sub-optimal.  Optimization would be possible but they would probably be a great source of implementation errors.  For what it's worth, I would love to see anonymous functions in some capacity even if we don't get full fledged closures.  The closer to closures the more useful they will be though.

Dan
November 09, 2001
> Question:  How would a closure declared in a method of an object be handled? I assume a "this" pointer to the object would be maintained in the closure's stack frame.

Right, except I think you mean the closure's environment object. The stack frame is created only when the closure is actually invoked.


> I don't really think a closure should be able to declare any
> variables which are visible to the enclosing function. (much like local
> functions)

Complete agreement.


> If only there were some way of determining whether a
> closure was safe to let use the normal stack frame, or if it needed one
> allocated from the heap!  [remainder omitted].

I have to admit I didn't completely understand the suggestion. In time something like this might be important to implement. At first I think it's ignorable as a second-order performance issue.


> Anyway I don't think a small heap allocation before iterating through 5000 objects will slow an application appreciably.  It is a tradeoff I'd gladly make in most situations where closures are useful.

Right, that's the point I was trying to make above.
November 09, 2001
a <a@b.c> writes:

> The closure is effectively a reference to a chunk of code and the chunk of data.  When all references to it go away, the chunk of data (and all references to said string) are destroyed by the GC.  It really isn't that complex to follow.  The complex part would be how the compiler decides what goes on the stack (not referenced by any closure) [and] what goes into heap allocated closure blocks.  I bet this could get harry if you declare several different closures in a given scope.

The rule is simple - any variable that is accessed by any closure
would go in the (single) environment object for that function
activation.  In cases like the function below the storage
for the variables in the nested (while) block would be pulled
up into the containing storage area.  This approach is well
understood and used in compilers all the time.  Yes?


> 	int f(){
> 		int a, b, c;
> 		int F1() = []{print (a, b);};
> 		while(elsewhere()){
> 			int a, d;
> 			F1 = [] {print(a, b, d);
> 		}
> 		int d;
> 		F1 = []{print(a, b, d);
> 	}
1 2
Next ›   Last »