Some Gotchas In Arithmetic Expression Evaluation : JavaScript
JavaScript arithmetic expressionsSolve a small problem in JavaScript #
This post is just for recollecting some of the basics of JavaScript. Let's start with a small JavaScript code. Here is the code –– Solve it with out using the console.
var a = 5, b = 3;
a = ( a - ( b = ( a = a + b ) - b ) );
Take your own time to come up with an answer before moving to the next section.
Analyzing the problem #
If your answer is a = 3 and b = 5
, this post is written for you. Open your favorite browser and fire up the console. Put the above code in the console and see the values of a
and b
now.
Stunned ? Yeah, The values of a
and b
are a = 0 and b = 5
now. Honestly I also got it wrong initially. I did ask this question to some of my friends ( who are in JavaScript circle ), and all of them gave me wrong answer.
Some flashback #
So, here is how I arrived this to particular question. Last week I was trying to write the code for an interview problem in JavaScript and it's a very common one –– How to swap values of 2 variables with out using a 3rd variable.
Let the variables be a = 5
and b = 3
. Swap the values of a
and b
with out using any 3rd variable .
Solution is simple . Just do the following arithmetic operations
a = a + b
b = a - b
a = a - b
This will do the job.
What I was trying is to write the entire expression in one single line. I wrote it like below.
Code 1 :
var a = 5, b = 3;
a = ( a - ( b = ( a = a + b ) - b ) );
Cool .. I thought it's done.
But I got surpriced when I tried it in the console. I was expecting final values should be a = 3 and b = 5
but the output was different. I got a = 0 and b =5
.
WTF ? Let me change the code a bit. I modified the code like this
Code 2 :
var a = 5, b = 3;
a = ( ( b = ( a = a + b ) - b ) - a );
This time I got the correct results a = -3 and b = 5
. So why the hell it didn't work for the first expression ?
The answer is : #
We're evaluating it wrongly. I mean we are not doing the way JavaScript engine does. I went to the EcmaScript specification and read the section for "Arithmetic Expression".
Expressions : Any valid unit code that resolves to some value.
Two things to note :
- Assignment operators are right to left associative. That means for the expression
a = b = 5
, the value5
will be assigned to variableb
and then assigned to variableb
. - Arithmetic and multiplicative operators are left to right associative. For the expression
c = a + b
, the value ofa
will be computed first, then goes tob
and computes it's value.
For our problem, if I draw the parse tree roughly, it will be like below.
=
/ \
a -
/ \
a =
/ \
b -
/ \
= b
/ \
a +
/ \
a b
Ideally parse tree doesn't contain the =
operator. I made it like this to understand how the parser start evaluating the expression.
In the above parse tree, all the =
operators are evaluated from right-to left ( that means the right node will be evaluated first and the value will be assigned to the left node ). On the other hand, arithmetic/multiplicative expressions are evaluated from left to right ( that means the values will be assigned from left and the arithmetic/multiplicative operation will be carried out ).
We can identify sub-expressions in our code. Basically, we can extract the expressions containing =
to sub-expressions. Hence the above parse tree can be re-drawn like below.
=
/ \
a -
/ \
a X
Where X
is the Sub-Expression 1 given below :
=
/ \
b -
/ \
Y b
Where Y
is the Sub-Expression 2 given below :
=
/ \
a +
/ \
a b
Let's see how JavaScript parser evaluate the value of a
finally.
Steps : #
Parser takes the main expression
a = a - X
and evaluated from left to right. At first, parser finds the variablea
and finds it's value. Now the parser moves to the next variableX
and try to calculate it's value. SinceX
is an expression, it need to be evaluated to form a primitive value.Note: To get the value, parser internally calls the GetValue of each operands
So, for the parser, the expression becomes like this :
a = GetValue( a ) - GetValue( Evaluate( X ) )
Which is :
a = 5 - GetValue( Evaluate( X )
Now it need to evaluate the expression
X
whereb = Y - b
. Here the first operandY
itself a sub-expression, so parser has to evaluate it first before calculating the value of the second operandb
.Let's evaluate the expression
Y
which isa = a + b
. This is straightforward and contains no sub expression , hence evaluated like this.
a = GetValue( a ) + GetValue( b )
This equals to :
a = 5 + 3
Finally the value of expression Y
becomes 8
.
- Coming back to step 2 where expression
X
needs to be completed. expressionX
is
b = GetValue( Y ) - GetValue( b )
Becomes like this :
b = 8 - GetValue( b )
Which is :
b = 8 - 3
Finally the value of b
and expression X
becomes 5
.
- So now all the sub expressions are evaluated , the main expression can be completed now.
The main expression was :
a = 5 - GetValue( X ) ; // value of X = 5 now
That means final value of a = 5 - 5
which is 0
.
- Finally the values of
a
andb
will becomea = 0 and b = 5
Now we're in the same direction with JS engine. We can apply what we learned for the Code 2 also.
Conclusion #
I didn't want to write this much long. All I wanted to recollect some of those basic stuff. Thanks for reading !!
References :
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- http://www.ecma-international.org/ecma-262/5.1/#sec-8.7
- http://es5.github.io/#x8.7.1
- http://stackoverflow.com/questions/19045411/can-somebody-explain-how-javascript-arithmetic-expressions-work