in reply to ||= oddity

@bar can't hold the result of ||= since @bar is an array and the result is a scalar. The LHS of ||= must be a scalar lvalue.

The following will do what you want:

@bar = (1,2,3) if !@bar;

I admit, the error message could be much clearer.

Replies are listed 'Best First'.
Re^2: ||= oddity
by throop (Chaplain) on May 28, 2008 at 22:45 UTC
    OK, once I knew what the answer was... it helped me find the answer in a manual. From 'Programming Perl, 2nd Edition', pp 92-93. It lists the assignment operators, including = and ||=, and says
    List assignment may be done only with the plain assignment operator, = +. In a list context, list assignment returns the list of new values +just as scalar assignment does. ...
    Hitting your thumb with a hammer - there's more than one way to do it!
Re^2: ||= oddity
by moritz (Cardinal) on May 29, 2008 at 12:43 UTC
    You may call me stupid, but why can't the scalar result of ||= be assigned to an array?

    This works:

    $ perl -wle 'my @a = 2; print @a' 2 $ perl -wle 'my @a = scalar 2; print @a' 2 $ perl -wle 'my @a = 2+2; print @a' 4

    So we can see that you can assign a scalar to an array, and it does what you mean - it creates an array with one item.

    But why can't you do it with the result of @array ||(1, 2, 3)?

      ... because it's been designed and implemented to operate the way it does — that's all :)

      I think the crucial difference is that the normal assignment operator (=) does not force scalar context upon its LHS (so the array remains an array, not the number of its elements), while ||= does.  It's not so much an issue of not being able to assign a scalar to an array, but rather the problem of the array no longer being (treated like) an array internally...

      If it did work, it would produce useless results.
      Given that (LHS ||= RHS) means (LHS = LHS || RHS),
      Then (@a ||= (1,2,3)) means (@a = @a || (1,2,3)) and thus (@a = $#a+1 || 3).
      Why would you ever want that.

      On the other hand, it would be useful to expand the definition of the ||= operator so that (@a ||= EXPR) means (@a = @a ? @a : EXPR).
      Similarly, it could be useful to expand the definition of &&= such that (@a &&= EXPR) means (@a = @a ? EXPR : ()).
      However, none of **=, +=, *=, &=, <<=, -=, /=, |=, >>=, .=, %=, ^=, //= and x= would be useful for arrays.

        You're mostly right, but actually LHS || RHS in list context evaluates RHS in list context. Indeed, if you try

        perl -we '@bar = (); @bar = @bar || (1, 2, 3); warn "(@bar)";'
        you see that the array is filled with the right values: (1, 2, 3); but that's still useless for indeed when the array isn't empty at the beginning,
        perl -we '@bar = (42, 5); @bar = @bar || (1, 2, 3); warn "(@bar)";'
        the or operator returns the length of the array so the array will contain only (2).

        Nice trap.

        However, none of **=, +=, *=, &=, <<=, -=, /=, |=, >>=, .=, %=, ^=, //= and x= would be useful for arrays.

        Actually, x= would be:

        $ perl -we '@bar = (42, 5); (@bar) = (@bar) x 5; warn "(@bar)";' (42 5 42 5 42 5 42 5 42 5) at -e line 1. $ perl -we '@bar = (42, 5); (@bar) x= 5; warn "(@bar)";' Can't modify array dereference in repeat (x) at -e line 1, near "5;" Execution of -e aborted due to compilation errors. $