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 executed 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With