in reply to Re^2: Why are "a ||= b" and "a = a || b" different?
in thread Why are "a ||= b" and "a = a || b" different?

No, it would not be simpler to change (a) ||= foo() to (a) = a || foo. I call your attention to Chapter 10 of On Lisp about pitfalls in macros as reference material and in particular, the part about Number of Evaluations. While you originally wrote (a) as your left hand expression, it could have been something else like bar() or (rand < .5 ? $a : $b). If you executed the left hand side multiple times, you could have inconsistent results.

# (a) could change entirely if run multiple times ( rand < .5 ? $a : $b ) = ( rand < .5 ? $a : $b ); # (a) might have side effects bar() = bar() || foo(); sub bar :lvalue { ... } # (a) might have side effects tie $a, ...; ($a) = $a || foo();

In all those cases it would be an error to cause the single mention of (a) to expand to multiple mentions. Internally perl evaluates your (a) once. It uses the expression's value as the input to the || operator and then it uses the same already computed expression as an lvalue. To see this under the hood and why, use the B::Concise module to look at your program's structure. Get Idealized optrees from B::Concise to see a simpler view. I annotated the ouput by hand.

perl -MO=Concise -e '($a) ||= foo()' | idealized-optree leave enter nextstate orassign # ||= gvsv # << $a sassign # scalar = entersub # foo() pushmark gv # *foo

⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Replies are listed 'Best First'.
Re^4: Why are "a ||= b" and "a = a || b" different?
by saintmike (Vicar) on Mar 04, 2007 at 21:27 UTC
    Thanks, diotalevi, your explanation of the side effects makes perfect sense.

    Do you have any thoughts about why

    ($ret1, $ret2) ||= foo();
    refreshes $ret2 and not $ret1 with the result of the evaluation of foo() in scalar context as mentioned by varian ?

    Update: typo fixed, thx diotalevi.

      You have a typo and meant ||= instead of =||.

      In the case of (A,B) ||= C, (A,B) || ... is the comma operator in scalar context. It evaluates the left argument A, then the right argument B and returns B. Thus you've just written A; B ||= C;.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

        D'oh! :). Thanks for clarifying.