1

Basically i am trying to access the predefined variable in a perl program. the variables are in the form a1 a2 a3 format. I want to access them in a loop. In the loop I will increment postfix scalar value

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

my ($a0,$a1,$a2,$a3)= (10,12,14,16);
for(my $i=0; $i<=3; $i++) {
    my $var = ${a$i};
    print $var;
}

WHAT I EXPECT: When I print $var in loop, I need the values 10,12 .. defined earlier.

WHAT I CAN NOT DO: I am aware that such situation can be handled with a hash. But I do not have any control over the variable naming, hence I can not use hash or change variable format.

I appreciate your help!

TobyLL
  • 2,098
  • 2
  • 17
  • 23
kpofcochin
  • 13
  • 4
  • 2
    I would really really really urge you to take another approach. Symbolic references (which these are) are nasty, dangerous and unnecessary. This article from 1998 is still as correct as it ever was: http://perl.plover.com/varvarname.html – Sobrique Feb 13 '15 at 12:55
  • @kpofcochin Perhaps it would help if you explained why you believe you have no control over the variable naming? We may be able to come up with a better solution to your problem if we understand that. – Scroog1 Feb 13 '15 at 13:39
  • possible duplicate of [How can I use a variable as a variable name in Perl?](http://stackoverflow.com/questions/1549685/how-can-i-use-a-variable-as-a-variable-name-in-perl) – AKHolland Feb 13 '15 at 14:56

4 Answers4

4

If you want to avoid turning off strict, you could use eval:

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

my ($a0,$a1,$a2,$a3)= (10,12,14,16);
for(my $i=0; $i<=3; $i++) {
    print eval "\$a$i";
}

Update: using more readable version suggested by Сухой27 in the comments

Scroog1
  • 3,539
  • 21
  • 26
  • Thanks buddy. it worked. I tailored it a bit to fit my requirements in following way! #!/usr/bin/perl use strict; use warnings; my ($a0,$a1,$a2,$a3)= (10,12,14,16); { no strict 'refs'; for(my $i=0; $i<=3; $i++) { my $var = eval "\$a$i"; print $var . "\n" if defined $var; } } – kpofcochin Feb 13 '15 at 10:05
  • Yes, it does :) Given the constraints, being bad doesn't appear of major concern. – Scroog1 Feb 13 '15 at 11:09
  • That said, this approach is reasonably good from a readability perspective (though that tends to be a matter of taste to some degree). – Scroog1 Feb 13 '15 at 11:17
  • 2
    Perhaps it would be better `print eval "\$a$i"`, but basically symbolic references are usually `XY problem` and make sense only to inexperienced. http://perl.plover.com/varvarname.html It was nonsense 17 years ago, and it is still a nonsense. – mpapec Feb 13 '15 at 12:09
  • 1
    Being a bad idea isn't a "major concern" for much the same reason as drinking a small amount of bleach won't do you much harm. It's still bad and wrong to turn off error checking because `you know better` because you're creating brittle unmaintainable code. And you don't need to, because perl has hashes. – Sobrique Feb 13 '15 at 12:53
4

Use an array instead of multiple similarly named variables, as this is their main use case,

use strict;
use warnings;

my @a = (10,12,14,16);
for my $i (0 .. $#a) {

  my $var = $a[$i];
  print $var, "\n";
}

alternatively you can use array of scalar references

use strict;
use warnings;

my ($a0,$a1,$a2,$a3) = (10,12,14,16);
my @a = \($a0,$a1,$a2,$a3);

for my $i (0 .. $#a) {

  my $var = ${ $a[$i] };
  print $var, "\n";
}
mpapec
  • 50,217
  • 8
  • 67
  • 127
2

What you are doing here is called a symbolic reference, and it is an EXTREMELY bad idea.

Please take a look through this article: http://perl.plover.com/varvarname.html

But the long and short of it is - using a variable as a variable name - which you're doing - is dangerous and unnecessary. It causes all sorts of potential problems in your code, including bugs in completely unrelated pieces of code. This is why strict won't let you do it.

More importantly - it's completely unnecessary, because perl has the hash as a native data type.

Instead of your code, consider instead:

my %h;
( $h{0}, $h{1}, $h{2}, $h{3} ) = ( 10, 12, 14, 16 );
foreach my $key ( sort keys %h ) {
    print "$key = $h{$key}\n";
}

Now, it's added a few characters to your code, but by doing so - you've created a lexically scoped namespace called %h. (I'd suggest calling it something more meaningful, personally - and definitely avoid $a and $b because they have special meanings).

But there is no danger of this namespace trampling over other parts of your code, and for bonus points - you no longer need your 'for' loop, you can simply iterate on keys instead. (So you always have the right number).

(Or as another user has suggested - just use an array)

Sobrique
  • 52,974
  • 7
  • 60
  • 101
1

You can get round strict's restriction on dynamic variable names like this.

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

{    
    no strict 'refs';

    my ($a0,$a1,$a2,$a3)= (10,12,14,16);
    for(my $i=0; $i<=3; $i++) {
    my $var = ${a$i};
    print $var;
    }
} 

I don't think this is a good idea, though!

user1717259
  • 2,717
  • 6
  • 30
  • 44
  • 3
    It really isn't. `refs` is in `strict` for a reason. It's because it's a really good way to create brittle, dangerous and unmaintainable code that'll cause future sysadmins and maintenance programmers to hunt you down. – Sobrique Feb 13 '15 at 12:54