Keep in mind that I am only an egg, and I am putting my intuition and
experience with similar languages to mind.  Perl6 might be doing
things differently than I expect.

On 11/22/06, Anatoly Vorobey <[EMAIL PROTECTED]> wrote:
To add some more confusion to what Yuval wrote:

In general, it doesn't seem to be very clear how inner (lexically)
subs see their enclosing lexical environments. Possibly I'm simply
very confused, in which case un-confusing me would be much appreciated.
Here're some code snippets.

{
  my $x = something();
  if $x==1 {
    ...code...
  }
}

In this case, when the inner block is entered from the outer as part
of execution, it's pretty clear how the inner block can see $x. There
can be many separate pads (local lexical environments) for the outer
block (for instance, if the outer block's a sub that recursed on itself)
with different values of $x, but only one of them was current just now
before we entered the inner block, and we can definitely arrange that
it be found as the inner block's ::OUTER.

My experience with other statically typed by extremely flexable
languages is that the pads tend to be arranged in (possibly
interconnected) linked lists.  In this example, I see potentially
three pads linked by the time ...code... is called:  One containing
the local variables defined in ...code..., one containing the visibly
defined $x, and one visible outside that scope.  A reference to $x in
...code... will traverse the linked list until it finds an $x,
presumably finding the one defined in the sample code.



With a closure, that works fine, too:

{
  my $x = something();
  return { $x++; }
}

As the inner block is cloned, the right pad for the outer block is
at hand, and $x can be copied from it (as a reference) to the
snapshot being built for the inner block.

Er, that's not how I see it.

When  {$x++;} is evaluated as a closure, it is for all intents and
purposes a function, with its own linked-list of pads.  The head pad
in the list contains nothing, and the next pad (the outer pad
belonging to the function) contains $x.  Since the head pad survives
the call, and it has a reference on the outer pad containing $x, that
outer pad survives as well.  However, since nothing else points to it,
the value of that particular $x is only visible to invokers of the
closure returned.



But what about inner named subs?

{
  my $x = something();
  sub foo { $x; }
}

&foo is visible outside the outer block because it's a package variable.
Presumably at compile time the block of foo was compiled to a Code
object, and &foo in the current package now points to that Code object
(or actually the Routine object storing the Code object inside it, but
the difference doesn't seem to be relevant here?). All this happens
before runtime starts. Now we call foo() from somewhere far away. What's
it going to see as $x? Certainly not anything meaningful, because the
assignment to $x might not even have run by now (if it's a part of a sub
that was never called), or it may have been run in many versions.

If I understand things, the sub foo {$x;} is not actually compiled
into a callable function until run time.  At which time, a pad
containing $x exists, which can be referenced by sub when converting
{$x;} into a Code object bound to the package variable foo.

My suspicion, without testing, is either (a) sub foo {$x;} in that
context doesn't actually define a package variable; (b) running that
block twice will redefine the package variable foo to the new
defintion (i.e., the new pad list); or (c) the redefinition will give
an error for redefining a function.

So it seems safe to say that foo() should see undef here as the value
of $x (perhaps because its idea of ::OUTER is really the compile-time
version of the outer pad). Now how about this:

I disagree.  foo should either be undefined (because the sub foo {$x;}
hasn't been run yet) or foo() should have the value of something(),
since it is pointing to an $x that was given that value.


{
  my $x = something();
  sub foo { $x; }
  foo();
}

Presumably in this case we do want foo() to see the right $x, current
at the time. How can it find that pad as its ::OUTER?

More importantly, if in the example when foo() is called from far away
it sees $x as undef, how can the following work at all (I'm assuming
it should work)? At package-level:

my $x = 1;
sub foo {
  $x;
}

Now we call foo() from a different package and we expect it to see
$x==1. But how is the situation different?

It's the scope.  The basic scoping rule I expect, regardless of actual
implementation, for a lexically scoped language, is that a variable
should refer to the closest lexically scoped variable declaration of
that name.  In all these cases so far, that would be to the $x
declared in the lexical scope the definition of foo is in.

I would expect that this would work:

my $x = 0;
sub foo {
 ++$x;
}
sub bar {
 my $x = 0;
 return {++$x;}
}
sub baz { my $x = 0;
 sub quux { ++$x; }
}

print foo();  #  1
print foo();  # 2
print bar()(); # 1
print bar()(); # 1
quuux = bar();
print quuux(); # 1
print quuux(); # 2
baz();
print quux(); # 1
print quux(); # 2

I figure one of us is wrong, and we've stated exactly what we think
should happen, so either way, someone will correct one of us.

Reply via email to