The obvious way to implement Perl5 "local" bindings in Parrot would be to:
1. Capture the old value in a temporary; 2. Use store_global to set the new value; 3. Execute the rest of the block; and 4. Do another store_global to reinstate the old value. This has a serious flaw: It leaves the new binding in effect if executing the rest of the block causes a nonlocal exit. Throwing can be dealt with by establishing an error handler that reinstates the old value and rethrows, but this doesn't begin to address continuations, not to mention coroutines, which can be used to jump to an arbitrary call frame without unwinding the stack. Then there are threads to consider. The naive approach makes each thread's dynamic bindings visible to all other threads, which may or may not be desirable (not, IMHO, but this is a language design issue). Worse, the final state of the variable depends on which thread exits first, which is surely a bug. Proposal: The only reasonable approach (it seems to me) is to keep dynamic binding information in the call frame. One possible implementation is as follows: 1. Add a dynamic_bindings pointer to the call frame. This points to a linked list of the frame's current bindings, each entry of which holds a name/value pair. Each thread's initial frame gets its dynamic_bindings list initialized to NULL. Each new frame's dynamic_bindings list is initialized from the calling frame's dynamic_bindings. Nothing additional need be done for continuation calling. The dynamic_bindings list needs to be visited during GC. 2. Modify store_global and find_global to search this list for the desired global. If found, store_global modifies the entry value, and find_global fetches the entry value. If not found, the existing hash is consulted in the current fashion (modulo namespace implementation). 3. Add a bind_global op with the same prototype as store_global that pushes a new entry on the dynamic_bindings list. 4. Add an unbind_global op that takes an integer or integer constant and pops that many entries off of the dynamic_bindings list. Bindings are effectively popped when the sub exists, but this op is still needed for cases where the end of a dynamic binding lifetime comes before the end of the sub. Advantages: + The scheme is robust with respect to continuations, threads, coroutines, and nonlocal exits. Each sub creates dynamic bindings that are visible only within its dynamic scope (i.e. subs that it calls, directly or indirectly), and not to other threads or coroutines. + The overhead is low: a pointer copy on call, none on return, and zero context switching overhead. For typical programs with little or no dynamic binding, these are the only costs. + The code that a human or compiler needs to emit is even simpler than that of the naive scheme described above. Disadvantages: + The time to fetch or store a dynamic binding is proportional to the depth of the dynamic_bindings stack, which could be considerable for languages that do a lot of dynamic binding. Conceivably, this could be addressed by using a language-dependant PMC class for the binding entry, and any such dynamic-binding-intensive language could define a per-frame class that acted as a linked list of hashes. But this could be postponed until it was needed, possibly indefinitely. If this is acceptable (and there isn't already a better plan), I will have time to address this over the holiday week. TIA, -- Bob Rogers http://rgrjr.dyndns.org/