Reputation: 1337
int a = 10, b = 20;
byte x = (a>b) ? 10 : 20;
The preceding code produces a Compile-Time error saying: Type mismatch cannot convert from int to byte.
It's weird that when i replace the expression (a>b) with (true) the code successfully compiles! Also when I replace the expression with literals (10>20) the code also works!!
Not only that but also when I explicitly type cast 10, 20 or even the whole ternary operator the code works too!
byte x = (a>b) ? (byte)10 : 20;
byte x = (a>b) ? 10 : (byte)20;
byte x = (byte)((a>b) ? 10 : 20);
What is exactly wrong with the expression (a>b)?
Note that equavalent code using if-else works fine.
int a = 10, b = 20;
byte x;
if(a>b) {
x = 10;
} else {
x = 20;
}
Upvotes: 2
Views: 759
Reputation: 3166
This may be redundant with all the other answers, but it's how I convinced myself. a.compareTo(b)
can clearly not be evaluated at compile time, and integer literals are always default int
:
String a = "a", b = "b";
byte x = (a.compareTo(b) > 1) ? 10 : 20;
produces the same compile time error:
error: incompatible types: possible lossy conversion from int to byte
byte x = (a.compareTo(b) > 1) ? 10 : 20;
^
Floating points are default double, so this also produces a similar error:
float x = (a.compareTo(b) > 1) ? 10.0 : 20.0;
Upvotes: 0
Reputation: 1462
Kind a similar to this, but not exactly. I tried going through language specification and few other resources, but there was no purely exact answer, on how the operand types are choosen by the compiler.
But assembiling all the info it seems that the:
byte x = (a>b) ? 10 : 20;
produces the error, because there's an implicit convertion of type int
to byte
.
In newer java versions the compilator shows:
error: incompatible types: possible lossy conversion from int to byte
This is because the second and third operand in (a>b) ? 10 : 20
is considered as int
. The basic numeric constants are always evaluated to int
and they need to be explicitly downcasted to byte
.
Casting the return (second or third) operands or the whole statement to byte prevents the error, because it explicitly shows to the compiler that data loss of casting int
to byte
shouldn't be taken into consiteration.
Casting second or third operand to byte
explicitly says that every return from that ternary operator should be treated as byte
.
Writing something like:
int aa = 100000000;
byte zz = aa;
//or
double dd = 10.11d;
long xyx = dd;
will result in same kind of an error.
The reason behind all of this is in that, the promoting of smaller primitive to upper one doesn't impact the deterministic result of a program, but downcasting (i.e. int to short) or dropping the floating point can output in different results.
See that, such declarations doesn't produce any error:
byte ooo = 100; //it throws an error if the value of ooo is higher than 127
//cause the `127` is the max value for byte type
int iii = ooo;
The line like:
byte x = (20>10) ? 10 : 20;
doesn't output in any runtime/compiller error, because while having explicit values provided to the condition compiler can simply evaluate condition which results in: byte x = 10
.
The dead code, aka unreachable statement in Java could be produced with:
try {
throw new Exception();
} catch (Exception e) {
throw new Exception(e);
System.out.println(); //compiler shows this line as unreachable
}
So, for a short conclusion, the number literals/constants are evaluated as int
type if they aren't explicitly assigned to the specific type. The byte x = 10;
works, because it explicitly says to assign 10
to byte type, and 10
is in scope of byte
type and doesn't leads to any data loss (assigning -129
or 10.1
throws an error).
The thing with byte x = (a>b) ? 10 : 20;
is that, the whole ternary expression isn't evaluated on fly, the compiler doesn't know if the values of a
and b
aren't being changed somewhere else. Stating explicit numbers or just true/false
in condition of ternary operator makes the result of an expression obvious to the compiler (and to developer eyes).
After a better look into spec of conditional operator it says:
The conditional operator ? : uses the boolean value of one expression to decide which of two other expressions should be evaluated.
Having this stated, the choosen result operator is evaluatd ONLY when the condition operator is evaluated (1st result if true, 2nd if false).
Explicit condition like 20>10
or true
is evaluated at compile time, so the exact, explicit value is assigned in case of byte x = ...
.
Why does something such small as:
int a = 10, b = 20;
byte x = (a>b) ? 10 : 20;
isn't being evaluated at compile time and throws an error?
As already stated number literals are evaluated to int
and in above assignment to x
variable isn't explicit (reminding the choosen result operator are evaluated after the condition is evaluated).
The compiler isn't something like a full static code analyzer, trying to request a compiler do to so could result in overcomplicated byte code.
Imagine some more complex example where the values of a
and b
are initialized in code but there are several if
statements which could change the values assigned to a
or b
. Then compiler must first check if any of if statement can be evaluated at compile time, to determine if there is a compiletime value for one of those variables and later produce conditions for the ternary/conditional operator
based on that if one of those values have changed. And in the result providing a lot of much complex code then it would do without such analyzes.
This is a very simple example, so for the dev it can look like wtf
, but for compiler preventing such case would be too much overhead, becasuse the compiler can't tell if the provided code is simple or not and cannot evaluate the variable values for conditions at compile time.
Upvotes: 0
Reputation: 40088
Because when the expression is directly specified with numbers like (10>20)
, then expression is evaluated at compile time itself and result value is assigned to byte variable. If you use any IDE you can see the warning of Dead code
in this expression
byte x = (20>10) ? 10 : 20 (Dead code); // because compiler know 20 greater than 10 and assigns 10 to x
But while using variables a,b
compiler doesn't know those values at compile time and the expression is evaluated at runtime. Since in java by default numeric values are represented as int
it is asking explicit type casting
byte x = (a>b) ? 10 : 20; //Type mismatch: cannot convert from int to byte
And i would suggest to read this for type casting with ternary operator
Upvotes: 2
Reputation: 7067
For the same reason you can do this:
int a = 10;
byte x = 10;
System.out.println("a: " + x);
but you can't do this:
int a = 10;
byte x = a; <-- java: incompatible types: possible lossy conversion from int to byte
System.out.println("a: " + x);
Direct assignment of an int
to a byte
using the literal is a narrowing conversion. It doesn't violate the type system because Java will happily lop the significant bits off a literal 10
and present you with a byte
.
But if you tell it a
is an int, it can't be a byte
(because a byte
isn't and int
).
Upvotes: 0