Re: Evaluation Order again.
by ikegami (Patriarch) on May 30, 2016 at 17:25 UTC
|
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.
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.
The only two possible orders consistent with the documentation are:
- $i → $i → ++ → $i → 2 → + → func() → my $rv → =
- $i → $i → ++ → 2 → $i → + → func() → my $rv → =
Update: Made clearer in response to the jerk's comment.
| [reply] [d/l] [select] |
|
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.
| [reply] |
|
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.
| [reply] [d/l] [select] |
|
|
|
|
|
|
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. | [reply] [d/l] |
|
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
| [reply] [d/l] [select] |
|
A reply falls below the community's threshold of quality. You may see it by logging in. |
Re: Evaluation Order again.
by Anonymous Monk on May 28, 2016 at 00:53 UTC
|
Even if you would like to blame the “exce
ssive” chaining, remember that expressions of the form
std::cout << f() << g() << h() usually result in chaining, after the overloaded operators have been resolved into function calls. It is the source of endless headaches. Newer library facilities such as std::future<T> are also vulnerable to this problem. when considering chaining of the then() member function to specify a sequence of computation.
As usual, C++ keeps introducing features that are supposed to fix previous C++ features.
| [reply] [d/l] [select] |
|
As usual, C++ keeps introducing features that are supposed to fix previous C++ features.
To be fair, C++ inherited the undefined execution order from C (from bcpl from B from ... ). It was the done thing to leave such implementation details "to the implementation"; and expect programmers to perceive all the situations where they might be bitten by that seemingly innocuous statement.
One of the driving forces behind this is one of the other goals of C++17; that of introducing implicit parallelisations. Another suggested benefit roundly poo hoo'd in that old thread.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
Don't take me wrong, I'm not saying that the order of evaluation of lists in Perl has a good reason to be undefined. I don't know if there such a reason; I suspect there isn't.
To be fair, C++ inherited the undefined execution order from C (from bcpl from B from ... ).
And inheriting various crap from C was also very much a feature (that needed - still needs - subsequent fixing)!
| [reply] |