JavaScript Puzzle - The Too Tidy Assignment |
Written by Ian Elliot | |||||||
Page 2 of 2
SolutionThe problem was isolated to a leaking of the local variable out into the global context. You can see this if you try the following program:
When the function executes the alert displays 0,0,0 which proves that the variables exist and have been initialized. However the second alert displays 100,0,0 which means that the global variables b and c have been set to zero. With this information now you should be able to see what is wrong. JavaScript is a functional language which means that expressions always return a value - even the assignment statement. So if try:
you will see 10 displayed as this is the result of the assignment. Now consider the evaluation of
The first part of the instruction is the var statement which declares the a to be a local variable. Next we have the initialization. When you write:
the order of events is that a is declared, the expression is evaluated and the value assigned to a. In this case we have to evaluate b=c=0. At this point things go wrong. The b variable isn't declared as local, it is a variable used in an expression without being declared, and so it is identified with the global variable b or a new global variable b is created, the same for c. Finally the 0 is evaluated and stored in c, which provides the result to store in b i.e. zero and finally this is also stored in a. All three variables end up being set to zero but b and c have been used as global variables. The reason for the error is to think of var as an operator with a higher precedence than assignment. If this were the case then the var would first be applied to create three local variables and then the assignments would be evaluated. However var is not even an operator, let alone having precedence over assignment, it is a statement and it evaluates the assignment before completing and declaring one variable as local. That is
is equivalent to
and the expression is b=c=0. PatternSo it is all JavaScript's fault. The programmer who attempted to make the simplification of the code was right to be annoyed that JavaScript had broken the rule about not doing unexpected things. Clearly:
should be interpreted to mean:
OK, if this is the case what about the programmer who wants to write:
Does this mean
No, clearly this is not about simple syntactic "sugar". Even if you throw in some semantics and say that you don't attempt to declare something that is an expression, i.e. the c+1, you still have a potential problem with:
unless you interpret it as
which is what JavaScript actually does! For example JavaScript does allow;
and this creates both b and a as local variables with b set to zero and a set to 1 i.e. it is equivalent to:
However:
doesn't work because b isn't defined when a is initialized i.e.:
Finally notice that:
does work and creates three local variables initialized to zero. Can you figure out why?
The point is that initialization combined with declaration isn't simple. In compiled languages declaration is a compile time operation and initialization is also usually, but not always, done at compile time. This results in a set of rules for what you can initialize variables to - basically the expression has to have a value at compile time. For example, the simplest thing to do is to restrict initialization to constants - but then the temptation is to extend things to variables with values that can be determined at compile time. This can become very complicated and JavaScript isn't the only language where declaration and initialization are messy. After you have pointed out what the troublesome expression actually means most JavaScript programmers don't think it's an aberration on the part of JavaScript - it seems logical. So how to avoid the problem? The most obvious way is to understand exactly what every JavaScript statement means in minute detail - obviously not possible. The alternative is not to try to tidy code to the point where it starts to be a matter of interpretation what the meaning is. In other words if it is a matter of what you expect of an little used construct then don't do it. Answer to final puzzle:
works is that a and b are declared as local variables without initialization. Then c is declared as a local variable and set to the result of the expression, which also sets a and b to zero.
<ASIN:1871962579> <ASIN:1871962560> <ASIN:1871962501> <ASIN:1871962528> More Puzzles
|