November 09, 2001 Re: Closures Part II - local variables outliving function activations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Pavel \"EvilOne\" Minayev | 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 Re: Closures Part II - local variables outliving function activations | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean L. Palmer | > 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 Re: Closures Part II - local variables outliving function activations | ||||
---|---|---|---|---|
| ||||
Posted in reply to a | 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); > } |
Copyright © 1999-2021 by the D Language Foundation