ambrus has asked for the wisdom of the Perl Monks concerning the following question:

When you do a list assignment, perl tries to do it efficently. Perl_newASSIGNOP in op.c checks if it can do ({@a=@b;push@a,@c;} instead of)  @a=(@b,@c); in a faster way This is usually possible, bot not in cases like ($a,$b)=($b,$a); or @a=(@b,@a);.

However, there is a bug(?) in Perl concerning this, when you type {*a=*b;@b=(1,2);@b=@a;$,=" ";print @a;}, it prints two undef's instead of 1 and 2. Is this a bug or a "feature", that is, is it intentional?

UPDATE My description of the optimization is wrong, as ysth said correctly. I don't actually know how this optimiztion works really.

Replies are listed 'Best First'.
Re: *a=*b;@a=@b problem
by tilly (Archbishop) on Nov 02, 2003 at 16:47 UTC
    That is clearly a bug where Perl got confused by the fact that the two arrays are the same when Perl didn't expect it. I would suggest using the perlbug utility to report it to p5p.
Re: *a=*b;@a=@b problem
by Anonymous Monk on Nov 02, 2003 at 16:36 UTC
    That is curious. And just to be a little more explicit:
    @a = (); @b = (); *a = *b; @b = (1,2); print "@a\n"; # 1 2 @b = @a; print "@a\n"; # uninit warnings (x2) print "@b\n"; # uninit warnings (x2)
Re: *a=*b;@a=@b problem
by ysth (Canon) on Nov 02, 2003 at 19:26 UTC
    Not sure what you are talking about. Perl does have checks in place to detect simple cases like ($a,$b)=($b,$a) and preserve the old values long enough to do the assignment as intended, but there is no @a=@b;push@a,@c optimization such as you describe.

    That said, there is clearly a bug here that should be reported.

Re: *a=*b;@a=@b problem
by Roger (Parson) on Nov 02, 2003 at 23:32 UTC
    I had a look at the Perl source code, this is what I *think* is happenning:

    When Perl detects a simple array/list assignment, it does a Perl_force_list on the left operand of the assignment, @b, including an implicit clear of the left operand, and hence introduced the side effect to the right hand side of the assignment, @a. Somehow the optimization engine decides that a temporary copy of the right handside is not required because it is a simple assignment.

    Thus this assignment
    @b = @a;
    is the equivalent of:
    @b = (); # temporary internal step @b = @a;
    And because the code defined *a = *b earlier, the assignment @b = () affected @a on the right hand side before the assignment, and hence the assignment @b = @a is really doing @b = () and @b = () again. Therefore the value of @a and @b after the assignment are both undef. But why does the resulting list contain two undef's? Ummm... this reminds me of another post by BrowserUk a few days ago on the side effect of print join '|', @a = %b... Another weired behaviour of Perl

    I modified the list assignment slightly -
    use Data::Dumper; *a = *b; @b = (1,2); @b = @b; # perl detects this is assigning into same variable print Dumper(\@b); @b = @a ? @a : (); # new assignment print Dumper(\@a); print Dumper(\@b);
    And I am getting the correct output:
    $VAR1 = [ 1, 2 ]; $VAR1 = [ 1, 2 ]; $VAR1 = [ 1, 2 ];
    From which an obersation is made: the right hand-side @a ? @a : () is evaluated first into a temporary copy of @a, before assigning into @b, thus preserving the original values of @a.

    My personal opinion is that we should be aware of the side effect. Report it as a bug or not, it's certainly an interesting recepie for another JAPH. :-)
Re: *a=*b;@a=@b problem
by rir (Vicar) on Nov 03, 2003 at 17:13 UTC
    I always try to remember to use other variable names; I don't expect that to address this problem. I am glad that I'm finally getting sensitized to this issue.