Lexical array retaining elements from previous function invocations

Discussion in 'Perl Misc' started by David McNerney, May 5, 2006.

  1. 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
     
    David McNerney, May 5, 2006
    #1
    1. Advertising

  2. David McNerney wrote:
    > 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
    --
    use Perl;
    program
    fulfillment
     
    John W. Krahn, May 5, 2006
    #2
    1. Advertising

  3. David McNerney

    Brad Baxter Guest

    David McNerney wrote:
    > 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];

    --
    Brad
     
    Brad Baxter, May 5, 2006
    #3
  4. "David McNerney" <> wrote in
    news::

    > 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 <>
    (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
     
    A. Sinan Unur, May 5, 2006
    #4
  5. 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!
     
    David McNerney, May 5, 2006
    #5
  6. 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.
     
    David McNerney, May 5, 2006
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. NOBODY
    Replies:
    2
    Views:
    403
    NOBODY
    Oct 30, 2004
  2. Replies:
    1
    Views:
    614
    Chris Smith
    Dec 5, 2005
  3. Replies:
    11
    Views:
    7,039
  4. Stefan Ram
    Replies:
    20
    Views:
    860
    Roedy Green
    May 2, 2006
  5. Richard Gration
    Replies:
    3
    Views:
    80
    Todd W
    Jan 11, 2005
Loading...

Share This Page