开发者

How does Perl decide which order to evaluate terms in an expression?

开发者 https://www.devze.com 2022-12-10 11:15 出处:网络
Given the code: my $x = 1; $x = $x * 5 * ($x += 5); I would expect $x to be 180: $x = $x * 5 * ($x += 5); #$x = 1

Given the code:

my $x = 1;

$x = $x * 5 * ($x += 5);

I would expect $x to be 180:

$x = $x * 5 * ($x += 5); #$x = 1
$x = $x * 5 * 6;         #$x = 6
$x = 30 * 6;
$x = 180;
180;

But instead it is 30; however, if I change the ordering of the terms:

$x = ($x += 5) * $x * 5;

I do get 180. The reason I am confused is that perldoc perlop says very plainly:

A TERM has the highest precedence in Perl. They include variables, quote and quote-like operators, any expression in parentheses, and any function whose arguments are parenthesized.

Since ($x += 5) is in parentheses, it should be a term, and therefore ex开发者_如何学编程ecuted first, regardless of the ordering of the expression.


The act of typing out the question yielded the answer to me: terms have the highest precedence. That means that the $x in the first chunk of code is evaluated and yields 1, then 5 is evaluated and yields 5, then ($x += 5) is evaluate and yields 6 (with a side-effect of setting $x to 6):

$x = $x * 5 * ($x += 5);
address of $x = $x * 5 * ($x += 5); #evaluate $x as an lvalue
address of $x = 1 * 5 * ($x += 5);  #evaluate $x as an rvalue
address of $x = 1 * 5 * ($x += 5);  #evaluate 5
address of $x = 1 * 5 * 6;          #evaluate ($x += 5), $x is now 6
address of $x = 1 * 5 * 6;          #evaluate 1 * 5
address of $x = 5 * 6;              #evaluate 1 * 5
address of $x = 30;                 #evaluate 5 * 6
30;                                 #evaluate address of $x = 30

Similarly, the second example reduces like this:

$x = ($x += 5) * $x * 5; 
address of $x = ($x += 5) * $x * 5; #evaluate $x as an lvalue
address of $x = 6 * $x * 5;         #evaluate ($x += 5), $x is now 6
address of $x = 6 * 6 * 5;          #evaluate $x as an rvalue
address of $x = 6 * 6 * 5;          #evaluate 5
address of $x = 36 * 5;             #evaluate 6 * 6
address of $x = 180;                #evaluate 36 * 5
180;                                #evaluate $x = 180


Whenever I have confusion about stuff like this I first pull out perldoc perlop, and then if I'm still not sure, or want to see how a particular block of code will get executed, I use B::Deparse:

perl -MO=Deparse,-p,-q,-sC
my $x = 1;
$x = $x * 5 * ($x += 5);

^D

gives:

(my $x = 1);
($x = (($x * 5) * ($x += 5)));
- syntax OK

So substituting values at each stage gives:

($x = (($x * 5) * ($x += 5)));
($x = ((1 * 5) * ($x += 5)));
($x = ((5) * (6))); # and side-effect: $x is now 6
($x = (5 * 6));
($x = (30));
($x = 30);
$x = 30;

So the fact that $x was temporarily set to 6 doesn't really affect anything, because the earlier value (1) was already substituted into the expression, and by the end of the expression it is now 30.


$x by itself is also a TERM. Since it is encountered first (in your first example), it is evaluated first.


The associativity of the * operator is leftward, so the left most term is always evaluated before the right most term. Other operators, such as ** are right associative and would have evaluated ($x += 5) before the rest of the statement.

0

精彩评论

暂无评论...
验证码 换一张
取 消