tags:

views:

247

answers:

7

In Perl, if a variable holds the name for another variable, how do I use the first variable to visit the other one?

For example, let

$name = "bob";
@bob = ("jerk", "perlfan");

how should I use $name to get to know what kind of person bob is? Although I'm not quite sure, my vague memory tells me it might related to typeglob.

+13  A: 

This is very bad practice. If you ever need to do it, it means you should refactor your code. Perhaps a hash with named keys would be better:

my %data = (
    'bob' => [ 'jerk', 'perlfan' ],
);
my $name = 'bob';

print $data{ $name }->[0], "\n";
print $data{ $name }->[1], "\n";

my $stringified = join ' and ', @{ $data{ $name } };
print $stringified, "\n";
depesz
+1 to avoid the bad practice is much better than to find way to make the bad practice happen
Haiyuan Zhang
That is what symbolic references are doing anyway: The evil is in the fact that by using symbolic references, one is treating the program's symbol tables as one's own private hash, which, it, of course, is not. So, **use a hash**. Don't use symbolic references. (I don't think this can be emphasized enough).
Sinan Ünür
+3  A: 

You really shouldn't have to do this, see depesz's answer for the alternative, but...

{
    no strict 'refs';
    print join(q{, }, @$name);
}

Yes, you can use a string scalar as a variable reference, and it looks up the variable by name.

You can also do this with typeglobs, see the Symbol module for an easy way.

derobert
+1 for the technically correct answer, and for agreeing that you should never do this.
Chris Lutz
+13  A: 

Several points:

  • You aren't talking about typeglobs, you are talking about symbolic references.
  • Don't use symbolic references -- they lead to hard to track down bugs.
  • In almost any case where symbolic references seem like a good idea, using a data structure based on a hash is the best approach.
  • Consider using Hash::Util to lock your hashes when you don't want to alter them.
  • Symbolic references don't work on lexical variables.
  • Typeglobs don't work on lexical variables.
  • Use lexical variables.
  • Don't use symbolic references.

See perlreftut for more on references (symbolic and otherwise). See perldsc for help using data structures. See perlmod for more on typeglobs. See perlsub for more on lexical variables.

Here's an example of using locked hashes to control access to data based on the content of a variable:

use strict;
use warnings;
use Hash::Util qw( lock_hash unlock_hash );

my %data;
lock_hash( %data );
#Altering %data is a fatal exception.

unlock_hash( %data );

%data = (
    'bob' => [ 'jerk', 'genius' ],
);
lock_hash( %data );


for my $name (qw/ bob  margaret /) {
    my $info = $data{$name}; # Fatal error when accessing data for margaret.
    print "$name is a\n";
    print map "\t$_\n", @$info;
}

All warnings aside, the syntax to use symbolic references should you need to use it (but you won't) is:

use strict;
use warnings;

my $name = 'bob';

our @bob = qw/jerk genius/;

my $qualities;

{   no strict 'refs';
    print "$name: ", @$name, "\n";
    $qualities = \@$name;
}

print "$name is a @$qualities\n";

Note that the array @bob is declared with our. Symbolic references only work with values in the symbol table. In other words, lexical variables do not work with symbolic references.

Just in case I haven't emphasized this enough, don't use symbolic references.

daotoad
Exactly. You easily could have stopped after the second bullet. I edited the question's title accordingly.
innaM
+1 for a technically correct and amazingly comprehensive explanation of how to do it and why not to.
Chris Lutz
A: 
no strict 'refs';
print "$name is @$name\n";
Hynek -Pichi- Vychodil
+3  A: 

See perldoc -q "variable name":

Beginners often think they want to have a variable contain the name of a variable. ...

Short answer: Don't. Long answer: Read the FAQ entry (which is also available on your computer). Longer answer: Read MJD's Why it's stupid to "use a variable as a variable name" (Part 2, Part 3).

Sinan Ünür
+2  A: 

Usually when you think you need to use symbolic references, you will be better served by using a hash (associative array).

use strict;
use warnings;

my %user = (
  'bob' => [qw' jerk perlfan '],
  'mary' => 'had a little lamb',
);

{
  for my $name (qw'bob mary susan'){
    if( exists $user{$name} ){

      if( ref($user{$name}) eq 'ARRAY' ){
        print join( ' ', @{$user{$name}} ), "\n";

      }else{
        print $name, ' ', $user{$name}, "\n";
      }

    }else{
      print "$name not found\n";
    }
  }
}

Results in:

jerk perlfan
mary had a little lamb
susan not found

If you think you really need to use symbolic references, this is a safer way to do that.

use strict;
use warnings;

# can't use my
our @bob = ("jerk", "perlfan");
our $mary = 'had a little lamb';

{
  for my $name (qw'bob mary susan'){
    if( exists $::{$name} ){
      my $ref = $::{$name};

      if( *{$ref}{ARRAY} ){
        print join(' ',@$ref), "\n";

      }elsif( *{$ref}{SCALAR} ){
        print "# $name is not an array, it's a scalar\n";
        print $name, ' ', $$ref, "\n";
      }

    }else{
      print "$name not found\n"
    }
  }
}

Which returns:

jerk perlfan
# mary is not an array, it's a scalar
mary had a little lamb
susan not found


You should notice that it is harder to symbolic references safely, which is why you shouldn't use them.

Unless of course you are an expert doing something advanced.

Brad Gilbert
A: 

Symbolic references are worth avoiding, but if you really want to use them, they have the same use syntax as regular references: see http://perlmonks.org/?node=References+quick+reference.

ysth