On Mon, Jan 16, 2006 at 02:38:14PM +0800, Audrey Tang wrote: : -----BEGIN PGP SIGNED MESSAGE----- : Hash: SHA1 : : I'm almost sure this had been covered before, but I failed to find a : reference in either the archives or in synopses, so here goes again: : : sub f ($x) { : sub g ($y) { $x + $y }; g($x); : } : f(10); # 20? : : Currently in Pugs, &g is built at BEGIN time when &f had not finished : building up its lexical environment, and as such fails to see the : runtime $x. The desugared form is: : : our &g; : BEGIN { &g := sub ($y) { $x + $y } } : : However, the following form does work in the Parrot, JavaScript and : Haskell runcore: : : sub f ($x) { : my sub g ($y) { $x + $y }; g($x); : } : : the reason it works is that &g's body is replaced every time upon &f's : entry. This is probably the expected behaviour.
Yup. : What would happen for the "our sub g" form, where it becomes possible to : call &g directly without entering &f? This shows Pugs's current behaviour: : : sub f ($x) { : our sub g ($y) { $x + $y }; g($x); : } : f(10); # 20 for sure : our &g; # gets visibility to &g : g(100); # 110 this time? : : So my questions are: : : * Is the treatment above sane? I think so, under the theory that &g is just a persistent form of the closure that happens to be cached in the symbol table rather than in some $ref variable. Though I can see "temp our &g" being put to interesting uses if &g is getting arbitrarily rebound at various points whenever &f is called... : * Does it make sense to change the undecorated "sub g"'s behaviour to : match "our sub g"? Yes, at least for any block that really is capturing a closure. Perhaps we need to distinguish those from "accidentally" nested top-level functions. But undecorated "sub" is more-or-less defined to be "our sub" anyway, just as with "package", "module", and "class" these days. The only difference is that "our" explicitly introduces a lexically scoped alias, while the undecorated form presumably doesn't. Though we could break that too, I suppose. : * If we insert a call to g() above without calling f() first, should it : assume an uninitialized $x, or throw an exception (Pugs currently does : the latter)? An exception is fine, modulo what I said about "accidental" nesting. When do you detect the condition? If the inner function can't reference $x, does it still fail? On the other hand, we can get into "eval" issues where it might or might not reference $x. I'm okay with requiring lexical scopes to have some existing relationship with dynamic scopes, especially when we know some initialization is required. Larry