Lexical array retaining elements from previous function invocations

D

David McNerney

Hello all... I'm wondering if anyone can help me make sense of some
strange behavior that just bit me. It would appear that it's possible
for a lexical array declared inside a function to retain values between
function invocations, if said array is declared but not initialized in
a single-line "if" statement. I've reduced my problem to the test case
below, which performs per the comments on Perl 5.8.6 (Mac OSX Darwin)
and Perl 5.8.5 (Red Hat Linux Enterprise 4 Update 1). Much thanks in
advance for any insight anyone can provide. -- David

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

sub function1
{
# PROBLEM HERE: if $_[0] is false here on successive invocations,
# @list is not cleared on the 2nd and later cycles, and any values
# added to it build up.
#
my @list = ("a") if $_[0];

# Uncomment this, and comment out the one above, and of course the
# strange behavior is gone
#
#my @list;

push(@list,"b") if $_[1];
print "list was: ".join(" ", @list)."\n";
}

&function1(1,1); # should print "a b", and does
&function1(1,0); # should print "a", and does
&function1(0,1); # should print "b", and does

# Problems begin here
#
&function1(0,0); # should print "", but prints "b"
&function1(0,1); # should print "b", but prints "b b"
&function1(0,1); # should print "b", but prints "b b b"
&function1(0,1); # should print "b", but prints "b b b b"
&function1(0,1); # should print "b", but prints "b b b b b"

# Ok again
#
&function1(1,0); # should print "a", and does
 
J

John W. Krahn

David said:
Hello all... I'm wondering if anyone can help me make sense of some
strange behavior that just bit me. It would appear that it's possible
for a lexical array declared inside a function to retain values between
function invocations, if said array is declared but not initialized in
a single-line "if" statement. I've reduced my problem to the test case
below, which performs per the comments on Perl 5.8.6 (Mac OSX Darwin)
and Perl 5.8.5 (Red Hat Linux Enterprise 4 Update 1). Much thanks in
advance for any insight anyone can provide. -- David

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

sub function1
{
# PROBLEM HERE: if $_[0] is false here on successive invocations,
# @list is not cleared on the 2nd and later cycles, and any values
# added to it build up.
#
my @list = ("a") if $_[0];

perldoc perlsyn
[snip]
NOTE: The behaviour of a "my" statement modified with a statement
modifier conditional or loop construct (e.g. "my $x if ...") is
undefined. The value of the "my" variable may be "undef", any
previously assigned value, or possibly anything else. Don't rely on
it. Future versions of perl might do something different from the
version of perl you try it out on. Here be dragons.



John
 
B

Brad Baxter

David said:
Hello all... I'm wondering if anyone can help me make sense of some
strange behavior that just bit me. It would appear that it's possible
for a lexical array declared inside a function to retain values between
function invocations, if said array is declared but not initialized in
a single-line "if" statement. I've reduced my problem to the test case
below, which performs per the comments on Perl 5.8.6 (Mac OSX Darwin)
and Perl 5.8.5 (Red Hat Linux Enterprise 4 Update 1). Much thanks in
advance for any insight anyone can provide. -- David

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

sub function1
{
# PROBLEM HERE: if $_[0] is false here on successive invocations,
# @list is not cleared on the 2nd and later cycles, and any values
# added to it build up.
#
my @list = ("a") if $_[0];

# Uncomment this, and comment out the one above, and of course the
# strange behavior is gone
#
#my @list;

push(@list,"b") if $_[1];
print "list was: ".join(" ", @list)."\n";
}

&function1(1,1); # should print "a b", and does
&function1(1,0); # should print "a", and does
&function1(0,1); # should print "b", and does

# Problems begin here
#
&function1(0,0); # should print "", but prints "b"
&function1(0,1); # should print "b", but prints "b b"
&function1(0,1); # should print "b", but prints "b b b"
&function1(0,1); # should print "b", but prints "b b b b"
&function1(0,1); # should print "b", but prints "b b b b b"

# Ok again
#
&function1(1,0); # should print "a", and does

This is a known issue. The answer is basically, don't do that.
Some people have taken advantage of this to intentionally
create static lexicals, but the behavior is not supported and
will likely quit working in future releases. Instead:

my @list;
@list = ("a") if $_[0];
 
A

A. Sinan Unur

sub function1
{
# PROBLEM HERE: if $_[0] is false here on successive invocations,
# @list is not cleared on the 2nd and later cycles, and any values
# added to it build up.
#
my @list = ("a") if $_[0];

If you had written this as:

if ( $_[0] ) {
my @list = ("a");
}

the problem with your code would have been clearer. Basically, putting
the declaration and initialization of @list in a compound if statement
causes ambiguity.

I am not sure why no warnings are emitted. I do remember a section in
the docs that deals with this but I am not able to locate it right now.
# Uncomment this, and comment out the one above, and of course the
# strange behavior is gone
#
#my @list;

push(@list,"b") if $_[1];
print "list was: ".join(" ", @list)."\n";
}

Rewrite this sub as:

sub function1 {
my @list;
@list = qw( a ) if $_[0];
push @list, "b" if $_[1];
print "list was: @list\n";
}
&function1(1,1); # should print "a b", and does

Don't use the ampersand in function invocations unless you know what it
does, and you specifically need that effect.

See perldoc perlsub

Sinan
--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
 
D

David McNerney

Thanks to everyone who replied. It does seem like a warning should be
emitted, but now that I know about it it won't bite me again at least!
 
D

David McNerney

Thanks for the info and the reminder.

I always use () with methods and functions, ie &foo(), never ever &foo,
and I've never dabbled in Perl prototypes, so the special behavior that
the ampersand brings with it hasn't bitten me in years. We usually use
object and class methods here, so it's kind of nice to have the & to
draw my attention to the rare use of a function in our code.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top