in reply to Lexical pad / attribute confusion

The following is mostly an educated guess, as I have not actually grokked the guts first hand.

It seems that both of these effects hinge on the duality of my having effects both at compile as well as runtime. Sprinkle a couple BEGIN { AttrTest->dump_lex('begin(1)') } in there and it becomes obvious that the pad gets fully populated during compilation, with all variables ever associated with the current pad being visible regardless of scope. In contrast, at runtime, the pad only contains those variables which are in scope - in fact, a variable doesn't appear in the pad before the entire statement during which it is declared has executed. It's for that reason that you can write my $x = 10; { my $x = $x; print $x } and get 10.

End educated guess.

Now with that, on to address each piece of the puzzle:

  1. INIT blocks are called after compilation has succeeded but before it is terminated. Therefor, they can see everything that's ever going to be in the pad they're associated with.
  2. In 5.6 the implicitly called MODIFY_HASH_ATTRIBUTES can see %foo because it is called during INIT - so the same rules as above apply.
  3. In 5.8 it can't, because the statement has not yet fully executed so the entry on the pad is not there yet.
  4. You're invoking the last dump_lex at runtime, outside the scope of either hash, so neither of them is visible in the pad.
I may well be wrong, but that picture seems to be seamless.

Makeshifts last the longest.

Replies are listed 'Best First'.
Re: Re: Lexical pad / attribute confusion
by djantzen (Priest) on Dec 22, 2002 at 01:37 UTC

    It's worth noting as well that CHECK and END blocks give the same results as we see in INIT. So in some way those portions of a program's lifespan are privileged. Also, whether the variables have attributes is incidental to whether peek_my can see them at runtime, for example,

    { package Baz; my %baz; }

    likewise only shows up when dump_lex is called from the special execution blocks.

    Now, a standalone my %quux is visible no matter where dump_lex is called from. This makes me think that perhaps there is loophole in PadWalker, and that there is still a way to keep your lexicals private; namely, by relying on perl's runtime enforcement of scope which I guess is just the same mechanism that makes it possible to write:

    sub foo { my $foo; { my $foo; } }

    That is to say, at runtime perl knows to differentiate the two $foos based upon where they are declared, despite being written on the same pad.

    Update: Duh. This isn't a loophole, but rather the documented, intended behavior. From the docs: It will only show those variables which are in scope at the point of the call. I must have read that line 10 times and it only made sense when I was about to step in the shower :)

      Yes, that part is just stuck into the opcode tree. This turns padsv calls from references to $foo into "the scalar located at location 'blah' in the pad". This is very clear if you start peeking at your code with B::Concise.


      Fun Fun Fun in the Fluffy Chair

Re^2: Lexical pad / attribute confusion
by adrianh (Chancellor) on Dec 22, 2002 at 01:58 UTC
    It's for that reason that you can write my $x = 10; { my $x = $x; print $x } and get 10.

    Ah. This makes the behaviour of the attribute handler make sense. Hadn't thought of that. It does mean that the documentation in attributes is an oversimplification when it says:

    my ($x,@y,%z) : Bent = 1;

    is equivalent to

    use attributes (); my ($x,@y,%z); attributes::->import(__PACKAGE__, \$x, 'Bent'); attributes::->import(__PACKAGE__, \@y, 'Bent'); attributes::->import(__PACKAGE__, \%z, 'Bent'); ($x,@y,%z) = 1;

    because things like this DWIM:

    my ($x,@y,%z) : Bent = (@y);

    Right then. With the attribute issue out of the way - I'm still confused why INIT can see everything. Since you can also see everything in CHECK and END blocks, which are run after compilation, I still don't understand what is going on.

      Since you can also see everything in CHECK and END blocks, which are run after compilation, I still don't understand what is going on.

      I think it's because at those stages in the program's lifecycle you don't have a runtime scope, or perhaps it's better said that the entire program is in their scope. They see everything written on a particular pad by the compiler, without perl hiding entries according to scoping rules. (Update: see diotalevi's remark above.)