Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Accessing lexically scoped variables from a subref

by /dev/urandom (Beadle)
on Dec 27, 2007 at 23:39 UTC ( [id://659268]=perlquestion: print w/replies, xml ) Need Help??

/dev/urandom has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks, Lets say I have a subref at my disposal, and the code in that subref includes a bunch of variables, that have been defined in the same block as the subref. Is it possible for me to access these variables somehow? I have the following code to illustrate my question correctly: A foo.pl file
#!/usr/bin/perl -w use strict; use Foo; my $i = 1; my $bar = 'foo'; my $foo = Foo->new; print "|", $foo->convert(sub {$i; return $bar}), "|\n";
And a Foo.pm module
#!/bin/false package Foo; use Devel::Peek; sub new { return bless {}, shift}; sub convert { shift; use B::Deparse; my $c = shift; my $b = B::Deparse->new("-d"); my @p = split /\n/, $b->coderef2text($c); print "FOOBAR: " . Dump($c) . " :BARFOO\n"; return $p[2] . '::' . eval $p[2]; } 1;
In this example, I want to get the value of the variables, that are used in the subref which is passed to the method of Foo (in this case, $i and $bar). Since the module is in a different file, I can't access the the variable ($i) content using eval. However, if I actually run the subref, it will return the correct value, so I think that in the subref's scope, these variables can be accessed. Is it possible for me to access these variables, maybe using some sort of B magic?

Replies are listed 'Best First'.
Re: Accessing lexically scoped variables from a subref
by chromatic (Archbishop) on Dec 28, 2007 at 00:23 UTC

    ISBN 0596526741 Perl Hacks #76 recommends the use of PadWalker, such that you can write something like:

    package Foo; use PadWalker 'closed_over'; sub convert { my ($package, $sub) = @_; my $vars = closed_over( $sub ); return join ', ', map { "$_ => $vars->{$_}" } keys %$vars; }
      This is indeed an excellent solution. The only problem is that it's not a pure perl module. However, after looking at the xs, the actual code for the closed_over function is rather small. For a simple subref:
      $i = 12; $a = sub { $i };
      All it took to get $i was this:
      B::svref_2object($a)->PADLIST->ARRAYelt(1)->ARRAYelt(1)->SV->object_2s +vref
      The only problem with using this is that I have no idea how it actually works. I just assumed that PADLIST contains all the local variables for that reference, but why the two-dimensional AV after that? Or for that matter, why is $i located on the second position of the second array? The others just return a B::SPECIAL, which I have no idea what its purpose is.
        The only problem with using this is that I have no idea how it actually works. I just assumed that PADLIST contains all the local variables for that reference, but why the two-dimensional AV after that?

        Short answer: the first array holds the names, the second holds the values.

        Longer answer:

Re: Accessing lexically scoped variables from a subref
by dragonchild (Archbishop) on Dec 28, 2007 at 04:34 UTC
    Generally, you want to really think long and hard before you violate the only (mostly and it's really hard) inviolable encapsulation that Perl provides. The better solution is fix what you're doing and provide proper accessors to those variables.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://659268]
Approved by almut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (6)
As of 2024-04-18 13:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found