bug in lexically scoped array not reset in foreach loop

G

Gavin Sherlock

Hi,

I had a script that I was trying to track a bug down in for ages, and
I've finally reached the conclusion that it really is a bug in Perl,
OR, I misunderstand what should happen: I have created a reduced test
case which is:

#!/usr/bin/perl

use strict;

my @ids = qw (XXX_foo XXX_bar XXX_baz foo bar XXX_foo baz);

foreach my $id (@ids){

my @result = &GetResult if $id !~ /^XXX_/;

print join("\t", @result), "\n";

if (!@result){

@result = ("Should never print");

}

}

sub GetResult { return ("blah") }

and what gets printed is:

poppy 107 > bug.pl

Should never print
Should never print
blah
blah

blah
poppy 108 >

I had thought that the my @result declaration should have reset the
contents of the array each time through the loop. It appears that it
doesn't, if the regex fails. Maybe this is the correct behaviour, in
that when the regex fails, the lexical declaration of my @result does
not happen, as well as the call to GetResult(). Of course this is
unintuitive (at least to me), because it means that in a strict
program, I now have access to a completely undeclared variable on the
next line. Am I crazy?

My workaround of course was to simply split it into 2 lines:

my @result;

@result = &GetResult if $id !~ /^XXX_/;

I get this result with the following Perl installs:

SW-90-732-818-2 104 % perl -v

This is perl, v5.8.1-RC3 built for darwin-thread-multi-2level
(with 1 registered patch, see perl -V for more detail)

belhaven 111 % perl -v

This is perl, v5.6.0 built for darwin

poppy 108 > perl -v

This is perl, v5.6.1 built for sun4-solaris

If anyone can tell me me why what happened is correct, I'd appreciate
it. If it's a bug, I hope the report is useful,

Cheers,
Gavin
 
U

Uri Guttman

GS" == Gavin Sherlock said:
my @result = &GetResult if $id !~ /^XXX_/;

this is a known issue with my and statement modifiers. my has a compile
time (declaration) and a runtime (assignment of empty or data) effect.

your condition there precludes the assignment of either undef or your
sub call when it passes.

there is an obscure (and not officially supported and dumb) technique
for making a static variable inside a sub:

my $foo if 0 ;

it will never be reset and can keep its value from call to call.

it is not proper perl and could be removed in future versions.

so you inadvertantly stumbled onto the same bad trick. the answer is
don't do that. declare the my variable first and then conditionally
assign to it
my @result;
@result = &GetResult if $id !~ /^XXX_/;

that isn't just a workaround, it is correct code.
it. If it's a bug, I hope the report is useful,

it is a known accidental misfeature. i would call it a bug. but it
doesn't need to be reported as it is well known among p5p.

uri
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top