Tuesday, 18 September 2012

Puzzle 9 Tweedledum

Now it's your turn to write some code. On the bright side, you have to write only two lines for this puzzle and two lines for the next. How hard could that be? Provide declarations for the variables x and i such that this is a legal statement:

x += i;


but this is not:

x = x + i;


Solution 9: Tweedledum
Many programmers think that the first statement in this puzzle (x += i) is simply a shorthand for the second (x = x + i). This isn't quite true. Both of these statements are assignment expressions [JLS 15.26]. The second statement uses the simple assignment operator (=), whereas the first uses a compound assignment operator. (The compound assignment operators are +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, ^=, and |=.) The Java language specification says that the compound assignment E1 op= E2 is equivalent to the simple assignment E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once [JLS 15.26.2].

In other words, compound assignment expressions automatically cast the result of the computation they perform to the type of the variable on their left-hand side. If the type of the result is identical to the type of the variable, the cast has no effect. If, however, the type of the result is wider than that of the variable, the compound assignment operator performs a silent narrowing primitive conversion [JLS 5.1.3]. Attempting to perform the equivalent simple assignment would generate a compilation error, with good reason.

To make this concrete and to provide a solution to the puzzle, suppose that we precede the puzzle's two assignment expressions with these declarations:


short x = 0;

int i = 123456;




The compound assignment compiles without error:

x += i; // Contains a hidden cast!


You might expect the value of x to be 123,456 after this statement executes, but it isn't; it's –7,616. The int value 123456 is too big to fit in a short. The automatically generated cast silently lops off the two high-order bytes of the int value, which is probably not what you want.

The corresponding simple assignment is illegal because it attempts to assign an int value to a short variable, which requires an explicit cast:

x = x + i; // Won't compile - "possible loss of precision"


It should be apparent that compound assignment expressions can be dangerous. To avoid unpleasant surprises, do not use compound assignment operators on variables of type byte, short, or char. When using compound assignment operators on variables of type int, ensure that the expression on the right-hand side is not of type long, float, or double. When using compound assignment operators on variables of type float, ensure that the expression on the right-hand side is not of type double. These rules are sufficient to prevent the compiler from generating dangerous narrowing casts.

In summary, compound assignment operators silently generate a cast. If the type of the result of the computation is wider than that of the variable, the generated cast is a dangerous narrowing cast. Such casts can silently discard precision or magnitude. For language designers, it is probably a mistake for compound assignment operators to generate invisible casts; compound assignments where the variable has a narrower type than the result of the computation should probably be illegal.

No comments:

Post a Comment

Your comments are welcome!