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