9

I ran into a situation earlier where I tried the following two bits of code:

int score = 100;
score = score * 1.05;

and

int score = 100;
score *= 1.05;

The first one failed (and obviously so, I'm trying to implicitly cast a float to an int). But the second one worked perfectly fine. The compiler didn't complain and I didn't get any runtime errors. Why does the second one work, while the first one doesn't? As far as I'm aware, x *= y is just a shorthand for x = x * y.

Simon Verbeke
  • 2,905
  • 8
  • 36
  • 55
  • 3
    Similar question but for `+=`: http://stackoverflow.com/questions/8710619/java-operator In short `score *= 1.05` works fine because it is the same as `score = (int)(score * 1.05)` – Pshemo Nov 12 '13 at 22:26
  • What compiler are you using? I just tried it on Visual Studio 2005 (Yes I am still using that, especially at work lol) and it works just fine. Only gave me a warning about conversion from double to int, but still ran fine. – John Odom Nov 12 '13 at 22:28
  • @Pshemo Aha, thank you! Didn't see anything related pop up in the side bar, so I assumed I was the first to ask this. – Simon Verbeke Nov 12 '13 at 22:29

3 Answers3

4

Compound assignment operators behave a little differently than their "expanded" version. Quoting the JLS, Section 15.26.2:

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

It is implicitly casted back to the type of the variable on the left side, so that there is no error casting a float to an int; it's already implicitly casted to an int.

That does not occur with the = operator, which is governed by the JLS, Section 5.2, Assignment Conversion:

Assignment contexts allow the use of one of the following:

  • an identity conversion (§5.1.1)

  • a widening primitive conversion (§5.1.2)

  • a widening reference conversion (§5.1.5)

  • a boxing conversion (§5.1.7) optionally followed by a widening reference conversion

  • an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.

It goes on to talk about a possible narrowing conversion being allowed, but only for constant expressions, and only for the constant expression being a byte, char, short, or int, neither of which is applicable here.

Community
  • 1
  • 1
rgettman
  • 176,041
  • 30
  • 275
  • 357
4

The first one

int score = 100;
score = score * 1.05;

is basically saying:

int score = 100;
score = (float)(score * 1.05);

This is because if you times a float with an integer then you get a float. This then cannot get assigned to an integer.

However

int score = 100;
score *= 1.05;

Basically means

int score = 100;
score = (int)(score * 1.05);

This is because you are not assigning the float, the calculation is done whilst assigning therefore first converts to an int.

Thats how it makes sense to me. Hope it helps

Mitch Dart
  • 1,333
  • 1
  • 12
  • 33
0

if you use:

int score=100;
score *=1.05;

This is equivalent to:

score=(int)(score*1.05);

Here it is explained in more detail: http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#15.26.2

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

krishna2642
  • 579
  • 1
  • 4
  • 10