Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re^2: Why does the first $c evaluate to the incremented value in [$c, $c += $_] ?

by smls (Friar)
on Mar 04, 2014 at 23:07 UTC ( [id://1077001]=note: print w/replies, xml ) Need Help??


in reply to Re: Why does the first $c evaluate to the incremented value in [$c, $c += $_] ?
in thread Why does the first $c evaluate to the incremented value in [$c, $c += $_] ?

Hm, no, I don't think that explains it.

Operator precedence requires, of course, that the += operator is evaluated before the , operator is evaluated, but it does not explain why the += operator is evaluated before the first argument to the , operator is evaluated.

And indeed, with other operators (i.e. other than ++ or += and friends), this does not happen. For example, . also has higher precedence than , but it does not cause the second decorate() call to happen before the first in the following example:

use feature qw(say state); sub decorate { state $counter = 0; return ++$counter . ':' . shift } my @a = ( decorate("foo"), decorate("bar") . "!" ); say "@a"; # prints "1:foo 2:bar!" and not "2:foo 1:bar!"

If I correctly understand the perlop paragraph quoted by Eily below, it appears that auto-increment operators only participate in the normal evaluation order as far as their return value is concerned, but their side-effect (modifying the variable) happens at an undefined time.

I really wonder why that is the case, though. Just as a function's side-effects happen when the function call is evaluated (from the point of view of the larger expression), I would have expected the side-effect of += to happen when it's the operator's turn to be evaluated in the evaluation order of the larger expression.

Replies are listed 'Best First'.
Re^3: Why does the first $c evaluate to the incremented value in [$c, $c += $_] ?
by Eily (Monsignor) on Mar 04, 2014 at 23:29 UTC

    That's because decorate has an even higher precedence (on the left of any operator except commas, and unless parenthesis are involved) so what happens is actually:

    (decorate("foo"), decorate("bar").'!') ((return $decorated_foo), (return $decorated_bar.'!')) ((return $decorated_foo), (return $decorated_bar_with_exclamation_mark +)) ($decorated_foo, (return $decorated_bar_with_exclamation_mark)) ($decorated_foo, $decorated_bar_with_exclamation_mark)
    (This is of course, not actual code, but just a representation)
    So first the calls to decorate are resolved, then the concatenation, and at last the values are added to the list. But the concatenation does not happen last.

    Edit: "removed" a bit about precedence being higher on the left of some operators, because it's late, and I'm not sure about what I'm saying.

      D'oh... Yeah, you're right.

      So, for the record, the evaluation order is in fact well-defined: It strictly evaluates higher-precedence operators first, before evaluating any operands of any less deeply nested part of the expression.

      That's the source of my confusion: I intuitively expected Perl to only use the operator precedence information to implicitly "add parenthesis" for disambiguation, but then evaluate the expression left-to-right, only recursing into nested sub-expression once they are encountered.

      That's two conceptually very different ways of defining evaluation order, but easy to miss because in practice it probably never makes a difference except in special cases involving += and friends.

      Well, almost never... :) Here's a demonstration of the evaluation order using tied scalars that report when they're being accessed:

      use warnings; use strict; package LoggingScalar { require Tie::Scalar; our @ISA = qw(Tie::StdScalar); sub FETCH { print "fetched: ".(${shift()} // '<undef>')."\n" } } tie my $x, 'LoggingScalar'; tie my $y, 'LoggingScalar'; tie my $z, 'LoggingScalar'; ($x, $y, $z) = qw(x y z); print "---\n"; my @a = ($x, $y . '!', $z);

      ...which outputs:

      --- fetched: y fetched: x fetched: z

      As for the mentioned perlop paragraph re. "undefined behavior", I suppose that refers to what Eily says here.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1077001]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (5)
As of 2024-04-25 11:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found