1

I'm new to Perl and I understand you can call functions by name, like this: &$functionName();. However, I'd like to use an array by name. Is this possible?

Long code:

sub print_species_names {
    my $species = shift(@_);
    my @cats = ("Jeffry", "Owen");
    my @dogs = ("Duke", "Lassie");

    switch ($species) {
        case "cats" {
            foreach (@cats) {
                print $_ . "\n";
            }
        }
        case "dogs" {
            foreach (@dogs) {
                print $_ . "\n";
            }
        }
    }
}

Seeking shorter code similar to this:

sub print_species_names {
    my $species = shift(@_);
    my @cats = ("Jeffry", "Owen");
    my @dogs = ("Duke", "Lassie");

    foreach (@<$species>) {
        print $_ . "\n";
    }
}
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Adam S
  • 8,945
  • 17
  • 67
  • 103

3 Answers3

15

Possible? Yes. Recommended? No. In general, using symbolic references is bad practice. Instead, use a hash to hold your arrays. That way you can look them up by name:

sub print_species_names {
    my $species = shift;
    my %animals = (
        cats => [qw(Jeffry Owen)],
        dogs => [qw(Duke Lassie)],
    );
    if (my $array = $animals{$species}) {
        print "$_\n" for @$array
    }
    else {
        die "species '$species' not found"
    }
}

If you want to reduce that even more, you could replace the if/else block with:

    print "$_\n" for @{ $animals{$species}
        or die "species $species not found" };
Sinan Ünür
  • 116,958
  • 15
  • 196
  • 339
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
4

You can achieve something close by using a hash of array references:

%hash = ( 'cats' => [ "Jeffry", "Owen"],
          'dogs' => [ "Duke", "Lassie" ] );

$arrayRef = $hash{cats};
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
0

You could also use eval here:

foreach (eval("@$species")) {
        print $_ . "\n";
    }

I should have made it clear that you need to turn off strict refs for this to work. So surrounding the code with use "nostrict" and use "strict" works.

This is whats known as a soft reference in perl.

ennuikiller
  • 46,381
  • 14
  • 112
  • 137
  • 1
    `Can't use string ("whatever was in $species") as an ARRAY ref while "strict refs" in use at ...` You probably meant `\@$species` but still, don't recommend string `eval` for things like this. And at least check for errors if you do. – Eric Strom Oct 27 '11 at 20:43
  • @ennuikiller, `eval` bypasses strict in this case if it's used correctly, and if you turned off strict you could use use `foreach (@$species)) { ... }` and bypass `eval`. – Ven'Tatsu Oct 27 '11 at 21:44
  • `strict` is catching an important error here. If you turn off strict, then the following transform takes place: `"@$species" -> "@main::dogs" -> '' -> eval('') -> ''` which will be silently failing to do what the OP wants because the variables are lexical. If the OP then switched to package variables, things get even worse. `"@$species" -> "@main::dogs" -> 'Duke Lassie' -> eval('Duke Lassie') -> tries to call Lassie->Duke() and hopefully fails -> ''`. As I said in my first comment, you probably wanted `eval('@'.$species)` which would have worked, but this all emphasizes why you shouldn't. – Eric Strom Oct 29 '11 at 02:06