perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

If I have the names of variables in an array, is it possible to print out Scalar variables with those names? Have tried a few variations but not had any luck. Seems like this should be "trivial" (I thought I'd done it before...a hallucination, maybe?). But something along the lines of:
my @EXPORTS=qw(DBG_ONE, DBG_TWO, DBG_FOUR); Readonly my DBG_ONE => 1; Readonly my DBG_TWO => 2; Readonly my DBG_FOUR => 4; foreach $flag (@EXPORTS) { printf "flag = %s, value = 0x%04x\n", $flag, ${$flag}; }
I've also tried getting the value using eval, but no luck with that either.

Thought defining the debug flags with something like:

my $bit=0; sub bit(){ my $s=2**$bit; ++$bit; $s; } sub dbg_flag ($) { my $flag=shift; eval sprintf ( "Readonly my \$$flag => 0x%04x push \@EXPORTS, \$$flag sub $flag () {\$_debug_ops & $\$flag}",$$flag ); } #then use it with something like @myflags=qw{DBG_ONE,DBG_TWO...}; foreach $flag (@myflags) { dbg_flag($flag); }
Even without the "sub" declaration in the eval, I kept getting a warning about push requiring a 2nd argument to push onto the first.

Not sure, but even if I did get the eval to work, I'd probably have to return it as a string from the creation routine and eval it while not in a sub -- possibly not in a "for loop" either -- so the definition would be outside the defining routine and outside the foreach loop. Might be able to concat evals together and execute whole bunch in one eval after building up code in the foreach loop...but never got that far not being able to use a variable name as an indirect name of a scalar. Thought this might get around my previously mentioned "'=28' not numeric" bug...but this wasn't any easier. *sigh*

I think I've been up a bit too long...:-)
Linda

Replies are listed 'Best First'.
Re: indirect/symbolic access in perl
by bruceb3 (Pilgrim) on Sep 20, 2007 at 12:22 UTC
    For the first chuck of code, I think it works better if you don't use comma in qw() and the DBG variables need to have a $ in front.

    Here are the changes that I made to the first chunk code and the output.

    bruce:1:~/tmp $ cat p.pl #!/usr/bin/env perl use strict; use warnings; use Readonly; my @EXPORTs = qw(DBG_ONE DBG_TWO DBG_FOUR) ; Readonly my $DBG_ONE => 1; Readonly my $DBG_TWO => 2; Readonly my $DBG_FOUR => 4; no strict 'refs'; foreach my $flag (@EXPORTs) { printf "flag = %s, value = 0x%04x\n", $flag, ${$flag}; } bruce:1:~/tmp $ ./p.pl Use of uninitialized value in printf at ./p.pl line 15. flag = DBG_ONE, value = 0x0000 Use of uninitialized value in printf at ./p.pl line 15. flag = DBG_TWO, value = 0x0000 Use of uninitialized value in printf at ./p.pl line 15. flag = DBG_FOUR, value = 0x0000

    In pondering why the uninitialized value warnings were being displayed I remembered that you can't use symbolic references on my variables. So change the my to our and retry ...

    #!/usr/bin/env perl use strict; use warnings; use Readonly; my @EXPORTs = qw(DBG_ONE DBG_TWO DBG_FOUR) ; Readonly our $DBG_ONE => 1; Readonly our $DBG_TWO => 2; Readonly our $DBG_FOUR => 4; no strict 'refs'; foreach my $flag (@EXPORTs) { printf "flag = %s, value = 0x%04x\n", $flag, ${$flag}; } bruce:1:~/tmp $ ./p.pl flag = DBG_ONE, value = 0x0001 flag = DBG_TWO, value = 0x0002 flag = DBG_FOUR, value = 0x0004

    Much better.

      Your last piece of code does not work - You are attempting to de-reference $flag, which yields undef, and prints zero.

      This ugly code below does work:

      #use strict; use Readonly; my @EXPORTS=qw(DBG_ONE DBG_TWO DBG_FOUR); Readonly::Scalar my $DBG_ONE => 1; Readonly::Scalar my $DBG_TWO => 2; Readonly::Scalar my $DBG_FOUR => 4; foreach my $flag (@EXPORTS) { printf "flag = %s, value = 0x%04x\n", $flag, eval( "\$" . $flag ); }
      but I hate evals, and you would be much better served by using something like
      Readonly::Hash my %DBG_Val => (DBG_ONE => 1, DBG_TWO => 2, DBG_FOU +R =>4);
      Update:bruceb3's code works fine. Ignore the code I posted, which is essentially identical to bruceb3's but uses eval (and thus avoids conflict with "use strict 'refs'). Do follow the advice regarding using a Readonly HASH - much safer, and probably closer to what you need to do.

           "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

        re code working -- I did it from memory -- it was one of the iterations I went through while trying to find a workaround for the Readonly "bug" that was giving me a cryptic runtime message ("=28" isn't numeric")....
      That's just weird...though I note someone seemed to get 'my' to work below by explicitly telling Readonly::(to use Scalar).

      I'm not clear on diffs between our and my -- I thought "our" was to allow a package to have 1 common var among all the objects of same type? (Vs. "my" giving separate copies).

      Especially odd as "our" only came in during 5.6...before that... "use vars?" maybe? Still, seems more than a bit arcane.

      Thanks,
      -l

      (at least I'm seeing I'm not entirely delusional...:-)).