Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

PadWalker's closed_over - but for our variables?

by LanX (Cardinal)
on Apr 03, 2021 at 15:24 UTC ( #11130774=perlquestion: print w/replies, xml ) Need Help??

LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

PadWalker is great for identifying and manipulating closed over private variables declared with my.

But what about package variables declared with our?

What's the best way to do this?

Do I have to parse the optree or do we have a Pad for our-lexicals too?

little demo which only works for private vars

DB<170> sub outer { package BLA; my $my=42; our $our=666; sub { prin +t "$my,$our" } } DB<171> outer()->() 42,666 DB<172> use PadWalker qw(peek_sub closed_over) DB<173> x peek_sub(outer()) 0 HASH(0x39d8ec8) '$my' => SCALAR(0x39d8dd8) -> 42 DB<174> x closed_over(outer()) 0 HASH(0x39d98b8) '$my' => SCALAR(0x39d92e8) -> 42 1 HASH(0x39d9168) # <- What is that,BTW? 1 => SCALAR(0x39d92e8) -> REUSED_ADDRESS DB<175>

PS: I'm aware of peek_our(), it just only works from inside the sub.

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re: PadWalker's closed_over - but for our variables?
by haukex (Bishop) on Apr 03, 2021 at 16:06 UTC

    Does talking about "closing over" (aliases to) package variables even make sense? Isn't one of the properties of lexical variables being closed over that they can't be accessed from the outsidecaller, which isn't true for "global" package variables? (In other words, your code could just as well be sub { print "$my,$BLA::our" }.)

    XY Problem? Or do you just want to get a list of all the variables that a coderef accesses?

      our variables are lexical package variables.

      "Lexical" describes the scope not how they are stored (private vs package)

      The docs are confused here.

      > can't be accessed from the caller,

      one still needs to know the package of an our-variable to access it

      > Or do you just want to get a list of all the variables that a coderef accesses?

      I need to introspect a coderef for the package vars used inside, you are right that it might not matter if they were declared outside with our.

      As already mentioned: PadWalker offers peek_our but only usable from the inside.

      edit

      so I effectively need peek_sub for package vars

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        our variables are lexical package variables. "Lexical" describes the scope not how they are stored (private vs package)

        I'm not sure I agree. At least in my mind, package variables are quite different from lexical variables: package variables are stored in the symbol table (and they can be inspected and manipulated there) and lexical variables in the pads (which aren't so easy to inspect, hence PadWalker). All that our does is create an alias to a package variable, that that alias happens to be lexical in scope is the only "lexical" thing about it, I think. Anyway:

        I need to introspect a coderef for the package vars used inside, you are right that it might not matter if they were declared outside with our.

        At the moment I'm not aware of an easy solution. Any general-purpose solution would fail in the presence of no strict, since I could write no strict; ${"${x}::${y}"} = "hello"; or even ${"a".int(rand(999))} and you'd never know which package variable I just accesed. Perhaps something PPI-based...? I don't have any other good ideas at the moment, perhaps inspiration will strike later.

Re: PadWalker's closed_over - but for our variables?
by haukex (Bishop) on Apr 04, 2021 at 08:55 UTC

    I looked at the current source of B::Deparse, and so far I've found two functions that are responsible for looking up variables. Hooking into these is a hackish way to get the variable names :-) There may be more things that need to be hooked (Update: and the final example shows it's not perfect), but perhaps this is a starting point:

    use warnings; use strict; use B::Deparse; use Data::Dump; use Hook::LexWrap; my $deparse = B::Deparse->new(); $deparse->ambient_pragmas(strict=>'all', warnings=>'all'); wrap 'B::Deparse::stash_variable', post => sub { my $rv = pop @_; my ($self, $prefix, $name, $cx) = @_; dd 'stash_variable', $prefix, $name, $rv; }; wrap 'B::Deparse::stash_variable_name', post => sub { my $rv = pop @_; my ($self, $prefix, $gv) = @_; dd 'stash_variable_name', $prefix, $rv; }; our $foo = "World"; my $bar = "Hello"; our @foo = 1..3; my @bar = 4..5; our %foo = ( abc => 444 ); my %bar = ( def => 222 ); our $ref = { xyz => 123 }; $deparse->coderef2text(sub { print "$bar, $foo\n"; print "@foo @bar\n"; print "$foo[1] $bar[1]\n"; my %dummy = %foo = %bar; print "$foo{abc} $bar{def}\n"; print $ref->{xyz}; }); __END__ ("stash_variable", "\$", "foo", ["\$foo"]) ("stash_variable", "\@", "foo", ["\@foo"]) ("stash_variable_name", "\@", ["foo", 0]) ("stash_variable", "%", "foo", "%foo") ("stash_variable_name", "%", ["foo", 0]) ("stash_variable_name", "%", ["main::ref", 0])

    I showed an example of PadWalker here.

      Thanks, coincidentally I already went the way of monkey patching Deparse in the meantime and have good results yet. :)

      Edit:

      Tho Hook::LexWrap might be a saner way to do it, need to get acquainted with this module...

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

Re: PadWalker's closed_over - but for our variables?
by xiaoyafeng (Deacon) on Apr 05, 2021 at 09:10 UTC
    There is a mistake which many people make: our does not declare a package variable, it just alias a package variable into current scope!, if you want to declare a package varable, you have to write $main::foo (without our and my!)




    I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

      Our does an implicit declaration initialization of the package variable if it is new.

      If you disagree, you should define what you mean with declaration in Perl.

      update

      "Declaration" is the act of defining type and attributes of a symbol for the compiler of a language.

      That's especially important for languages where all symbols are barewords but Perl has sigils and variables are dynamically typed.

      A "fully qualified name" in Perl like $pck::scl doesn't need to be declared for the compiler, because everything is known at compile-time. It's only initialized at first encounter into the STASH (symbol table) with a value (= undef by default)

      So talking about the "declaration of a package var" is highly confusing.

      BUT if you write our $var you are declaring for the compiler how to treat the symbol $var

      To cite the docs:

      An our declaration declares an alias for a package variable that will be visible across its entire lexical scope

      Like with my this declaration is recorded in a hash like structure called a Pad which is an attribute of the scope (= surrounding "block" resp. function).

      The big difference to my is that the our var is NOT destroyed (the ref is freed and the data erased from memory) at the end of the scope, because it is still referenced in the STASH of it's namespace.

      I.e. next time you'll encounter an our $var in the same package it'll continue pointing to the same ref.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        I totally agree what you point out on the update. ;) what I want to empasize is the declaration of our acatually means declaring a alias to a a pkg variable, not declare a package variable itself.





        I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://11130774]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2021-04-18 18:46 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?