Question

Why does this code not run properly? I was trying to write code to print the last value of each array here, and it seemed like I was just writing the same lines over and over again with different variable names. I then tried to do something like this, where I could just take a loop have it 'build' the variable name for me, and then evaluate it as if it was actual Perl. But the array fails to initialize and throws out an error when I try and treat it like an array.

Now, perhaps I'm confused as to the usage of 'eval'. But it seems like this should work, and I'm a bit stumped. What am I doing wrong? I need to tell perl to evaluate "@a" (or whichever one I'm on) and return @a.

#!/usr/bin/perl -w                                                                                                                           
use strict;

my @a = (1, 2, 3);
my @b = (4, 5, 6);
my @c = (7, 8, 9);
my @letters = ('a'..'c');

foreach (@letters) {
    my $varname = '@' . "$_"; ## Generate the variable name I want to use. Returns '@a' or '@b' or '@c' just fine.
    my @foo = eval { $varname }; ## Only returns '@a' or '@b' or '@c' again.  =\
    foreach (@foo) {  
        print 'The last element of the array is: ' . $foo[-1] . "\n";  ## returns only the array name.  e.g. '@a' See previous comment.
    }
}

The proper output of this program should be 36912 if I'm not mistaken.

Was it helpful?

Solution

You want eval $varname, not eval { $varname }.

But please read Why it's stupid to `use a variable as a variable name'.

Better would be to do use references - something like:

#!/usr/bin/env perl
use strict;
use warnings;

my @a = (1, 2, 3);
my @b = (4, 5, 6);
my @c = (7, 8, 9);
my @all = (\@a, \@b, \@c);

foreach (@all) {
    my @foo = @$_;
    foreach (@foo) {
        print "The last element of the array is: $foo[-1]\n";
    }
}

OTHER TIPS

Your problem can be explained by reading the documentation for eval, as you were using the 2nd form instead of the 1st form:

  • eval EXPR
  • eval BLOCK
  • eval

    In the first form, the return value of EXPR is parsed and executed as if it were a little Perl program. The value of the expression (which is itself determined within scalar context) is first parsed, and if there were no errors, executed as a block within the lexical context of the current Perl program. This means, that in particular, any outer lexical variables are visible to it, and any package variable settings or subroutine and format definitions remain afterwards.

    ...

    In the second form, the code within the BLOCK is parsed only once--at the same time the code surrounding the eval itself was parsed--and executed within the context of the current Perl program. This form is typically used to trap exceptions more efficiently than the first (see below), while also providing the benefit of checking the code within BLOCK at compile time.

So basically, my @foo = eval { $varname }; is equivalent to my @foo = do { $varname }; except that it does error trapping. Obviously a simple scalar in a void context isn't going to throw any errors, so it's equivalent to my @foo = $varname;.

If you wanted the other, you have to use my @foo = eval "$varname";

Regardless, you shouldn't be using eval at all. It's not a tool necessary for beginner programmers, and will only get you in trouble. The only time it's acceptable for a beginner to eval is in the RHS of a regular expression, s{search}{ BLOCK }e;

Therefore follow tobyink's advice and use references.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top