x = x*0.90; gives lossy conversion error. x*=0.90; does not. Why? [duplicate]
Asked Answered
P

3

25

I have written the code:

int x = 18;
x *= 0.90; 
System.out.println(x);

This code printed 16

However, when I wrote

int x = 18;
x = x * 0.90; 
System.out.println(x);

it gave me the following error: incompatible types: possible lossy conversion from double to int

I expected both of these code examples to result in the exact same error as x *= y; is the same as x = x * y;, but x *= 0.90; somehow works and x = x * 0.90; does not. Why is this the case?

Paymar answered 8/12, 2023 at 4:15 Comment(0)
C
30

Because the Java Language Specifcation (JLS) says so. It's a bit odd, but, when using the compound assignment operators (*=, +=, etcetera), the cast is implied.

See JLS §15.26.2 which clearly shows the cast in the example right at the top of that section.

Why does it do that? Well, I don't think SO is the right place to ask 'what were the designers thinking 30 years ago when this part of the JLS spec was written up'.

EDIT: This answer used to mention 'probably because of C' but as comments show, no, in C neither form requires an explicit cast.

Cheyennecheyne answered 8/12, 2023 at 4:23 Comment(10)
I don't think you can blame C for the discrepancy. Historically, C has been very forgiving with type conversions, having extensive type conversion rules for arithmetic operations. That is, C produces no errors for either standard multiplication or compound operations in this case. Both values are (silently) promoted to floats for the multiplication, then smashed down to ints when placed back into the variables. -- The fact Java has an error for * but not for *= is entirely on the Java creators, and has nothing to do with Thompson & Ritchie. (P.S. Ritchie died 10+ years ago.)Shiah
Agree with R.M. You can test that both work in C; the reason is that Java changed *= to have a cast for some reason.Distributee
Added: and Java also changed = to not do narrowing casts.Distributee
In C, x = x * 0.90 and x *= 90 are identical, so this didn't come from C.Meliorism
@Shiah Actually, Dennis Ritchie died in 2011, a week after Steve Jobs.Meliorism
I suppose, they considered it impractical to insist on an explicit cast in case of … *= …, because, well, how would the syntax look like? Note that the same applies to the ++ and -- operators.Xe
I have corrected the answer to remove the reference to C.Cheyennecheyne
"Why does it do that? Well, I don't think SO is the right place to ask 'what were the designers thinking 30 years ago when this part of the JLS spec was written up'." << If StackOverflow really is a bad place for that question, there I think it would be a great question for langdev.stackexchange.com . Note that Java is hardly the only language where a = a * b; and a *= b; are not completely synonymous, or a += b; and a += b;. For instance in python3, if a is a mutable type (such as list), then a += b and a = a + b are always different.Laugh
At least a couple of the JLS architects are (or at least have been in the past) active on SO, so there is actually a small but noticeable chance that you could get an objective, non-speculative answer to that "why".Gausman
@Laugh "What were the language designers thinking 30 years ago" is also on-topic on Retrocomputing – though I think Programming Language Design and Implementation would be more appropriate for more theoretical questions like this, where now-obscure hardware knowledge isn't so critical.Purge
C
10

The designers of Java generally valued consistency over the sensibility of particular cases. Given byte a,b; int i;, the expression a & b will be evaluated by converting the operands to int, and would thus yield a result type of int. There was thus no nice way to require a cast for a = (byte)i; but not require one for a = (byte)(a & b);. If the expression were written as a &= b;, there would have been no way to cast the result of the & operator before performing the assignment. Rather than make the &= (and other compound assignment) operators useless with byte, short, or char, Java opted to instead include an implicit conversion between the result of the combining operator and the use of the result for the assignment.

Coppinger answered 8/12, 2023 at 19:10 Comment(0)
M
-1

*The compound assignment operator x = 0.90; is designed to be shorter and to handle type conversion implicitly and it's helping to avoid potential lossy conversion errors.

  • Example 1: Lossy conversion error with explicit assignment

x = 5 # Assume x is an integer

x = x * 0.90 # Error: lossy conversion from float to int

  • Example 2: No error with compound assignment

x = 5 # Assume x is an integer

x *= 0.90 # No error: implicit conversion handled by the compound assignment

Monotint answered 8/12, 2023 at 19:8 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.