in reply to Why are "a ||= b" and "a = a || b" different?

Saintmike, first of all thank you for bringing up this excellent challenge. As the answers of other monks did not seem to provide a concise answer I decided to dig into the issue to learn why. Sure enough Perl must have acted consistent as usual?

It turns out that your assumption is not correct. In both scenarios foo() result is used in list context. This snippet of code will demonstrate it:

#!/usr/bin/perl -w use strict; sub foo { return (10,11,12,13); } my $ret = 0; my $ret2= 0; # EXPRESSION A ($ret,$ret2)||= foo(); print "ret=$ret ret2=$ret2\n"; # ret2 returns 13, last element of list # ret remains unused (warning raised) $ret=0; # EXPRESSION B ($ret) = ($ret) || foo(); print "ret=$ret\n"; # returns 10, first element of list

What drives the whole problem (and solution) is that the '||' operator returns the last value evaluated. And that's where the catch is!
Expression A evaluates the last element of ($ret,$ret2) against the last element of what foo() returns. Since what is listed on the lefthand of the '=' is part of the expression, only the last element of the left-hand operand gets updated.
In Expression B first Perl evaluates the expression on the righthand of the '='. The last values of the (righthand) operands are compared and because $ret is zero this option is discarded and the next operand, foo() is taken. So the result of the expression is foo's list (yes, all elements!). Subsequently this result gets assigned to what is on the lefthand of the '='.

All this shows that it can be tricky to use the '||' operator in a list context. The net result is not obvious and probably one wants to surround any such expression with a little bit of inline documentation so ease code maintenance. Frankly, for myself I would stay away from the construct where possible (except maybe in a nice JAPH).

Update: 'YAPH'=~s/Y/J/

Replies are listed 'Best First'.
Re^2: Why are "a ||= b" and "a = a || b" different?
by saintmike (Vicar) on Mar 03, 2007 at 18:02 UTC
    To verify whether a function is called in list context or scalar context, use wantarray.

    Here's a snippet of code to verify my assumption:

    my $a; ($a) = ($a) || foo(); ($a) ||= foo(); sub foo { wantarray ? print("list\n") : print("scalar\n"); return 0; }
    and it prints
    list
    scalar
    
Re^2: Why are "a ||= b" and "a = a || b" different?
by sgifford (Prior) on Mar 03, 2007 at 18:04 UTC
    It looks like there really is a difference in the calling context:
    #!/usr/bin/perl use Carp; my $ret; undef $ret; ($ret) ||= foo(); warn "ret is $ret"; undef $ret; ($ret) = $ret || foo(); warn "ret is $ret"; sub foo { carp "Want " . (wantarray ? "array" : "scalar"); (1,2); }
    outputs:
    Want scalar at t3 line 17 main::foo() called at t3 line 8 ret is 2 at t3 line 9. Want array at t3 line 17 main::foo() called at t3 line 12 ret is 1 at t3 line 13.
      void is false
      my $w = wantarray; $w = defined $w ? ($w ? 'list' : 'scalar') : 'void'; carp "wantarray : $w ";

        Why copy the value of wantarray into a temporary? You're just adding visual and other overhead.

        ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re^2: Why are "a ||= b" and "a = a || b" different?
by Anonymous Monk on Mar 03, 2007 at 11:00 UTC