in reply to Evaluation Order again.

While the operand evaluation order ("the execution order of subexpression") hasn't changed since you asked your earlier question, it's actually defined for many operators[1].

Your earlier question proposes the following expression as an example of where operand evaluation order is undefined:

my $rv = func( $i, ++i, $i+2 );

However, operand evaluation order is almost completely defined for that statement. Most relevant is the following passage from the documentation:

Binary "," is the comma operator. [...] In list context, it's just the list argument separator, and inserts both its arguments into the list. These arguments are also evaluated from left to right.

The only ambiguity is which of the addition's operands is evaluated first[2].

As for why the order is undefined for things such as addition? Probably because there's very little point in doing so. There's also the question of what criteria would be used to decided what would be ordered and in which order. Without having a reason to order, it's hard to know how it should be ordered. It's far better to leave the order as undefined as possible to provide the most flexibility should we ever add a feature that prefers lack of ordering or some ordering.


  1. It's explicitly defined for the comma operator, logical operators and the flip-flop operators. It's implicitly defined for assignment operators. It's not defined for arithmetic operators, comparison operators and the range operators.

  2. The only two possible orders consistent with the documentation are:

    • $i$i++$i2+func()my $rv=
    • $i$i++2$i+func()my $rv=

Update: Made clearer in response to the jerk's comment.

Replies are listed 'Best First'.
Re^2: Evaluation Order again.
by oiskuu (Hermit) on May 30, 2016 at 20:03 UTC

    See also: Why does the first $c evaluate to the incremented value in [$c, $c += $_] ?

    I read you as follows:

    • Functions take an argument list, where the comma is an argument separator. The argument separator, however, is the same as comma operator, therefore the evaluation order is documented and guaranteed.
    • Functions take a generic list as arguments, and that is all there is to it. No other rules, no specifications to consider.

    Please correct me if I misread you. Also, it wouldn't hurt to provide some citations or pointers to materials where the conceptual design is laid out.

      Sounds right, except there is "another rule".

      The argument list is just a generic expression evaluated in list context ("LIST"). That expression is commonly a chain of comma operators (e.g., f(1,2,3)), but is not limited to that (e.g., f(@a)).

      The exception is when prototypes are used. Prototypes can restrict the expression that can be provided, and they can alters how they are evaluated.

        Perl documentation is typically skimpy when it comes to formal specifications. Handwaving and C terminology is used ("undefined behavior") where such parallels can be drawn. I suppose it is prudent to make no promises one might renege later.

        So this is certainly news to me. I thought one couldn't really depend on their order of evaluation. If there was such a strong guarantee, I'd have expected the docs to be clear on this. A note in perlsub, perlop or perlfunc; heck, why not all three.

        "Subroutine arguments are evaluated from left to right."

        Considering that you speak with something of an authority, would it be too much to ask of you to please update the perl documentation with the relevant detail? A prominent, unequivocal, unambiguous notice to this effect would be lovely to have.

Re^2: Evaluation Order again.
by Tanktalus (Canon) on May 30, 2016 at 19:11 UTC

    If I'm reading your statement correctly, and given a func that looks like this:

    sub func { print $_, ' ' for @_; print "\n"; $_[2]; }
    And given $i starting at, say, 3, what would you suppose the output to look like? The way I read your your ordering is that I should expect "3 4 6" (once we've added the missing $ to the second parameter). However, that's not what I get. I get "4 4 6" consistently across perls going back to 5.8.8 (which is as far back as I've got here). So either my interpretation of your statement is wrong or the documentation doesn't match the implementation. I'm not sure which.

      Your incorrect expectation has nothing to do with operand evaluation order; it's that you didn't take into account that Perl always passes by reference.

      The following demonstrates that the operand evaluation order used is the one that was documented.

      use Data::Alias qw( alias ); sub func { print $_, ' ' for @_; print "\n"; $_[2]; } { my $i = 3; func( $i, ++$i, $i+2 ); } { my $i = 3; local @_; alias push @_, $i; alias push @_, ++$i; alias push @_, $i+2; &func; }
      4 4 6 4 4 6

        Ah, of course. That distinction becomes important so rarely for me that it's easy to forget. So, to remove the referencing, and make it show up "as expected", I just add zero to each item, and I get what I expect:

        use strict; use warnings; sub func { print $_, ' ' for @_; print "\n"; $_[2]; } my $i = 3; my $rv = func(0+$i, 0+ ++$i, 0+$i+2);
        And now I get my "3 4 6" - and everything makes sense again. See? I knew I did something wrong ;)

A reply falls below the community's threshold of quality. You may see it by logging in.