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