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. 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. 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. 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: { 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? I thought I had an argument as to why it could be different: we could say that a named sub's block is a closure like any other block, and it's closed already at compile-time; at that time $x is captured by foo(); and since the file-level code is only run once, its runtime pad is the same as its compil-time pad, therefore when $x is later assigned 1 at runtime, it's the same Scalar object it was (with value undef) at compile-time, and foo() sees that change. But now after re-reading S04 and S06 I see that's hopelessly muddled and wrong in at least two ways. First, S04 says that named subs don't clone anything until a reference is taken to them - until then they're just blocks of code. Second, S06 also says that the (file|package)-level code isn't necessarily run once, it's implicitly part of a &MAIN sub ("The outermost routine at a file-scoped compilation unit is always named &MAIN in the file's package."), unless &MAIN had been redefined; and could in principle be called again. So that $x doesn't necessarily exist, at runtime, in just one pad. It seems that the above is really something like sub &MAIN { my $x = 1; sub foo { $x; } } But then it becomes _exactly_ identical to the case before where it seemed inevitable that calling foo() from a faraway place doesn't let it see $x==1. So how is this different here and how can it work? Thanks, Anatoly.