On Mon, Jan 16, 2006 at 02:38:14PM +0800, Audrey Tang wrote:
: 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.


: 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


Reply via email to