Bu Saeed
Bu Saeed

Reputation: 1337

Type mismatch with byte variable using ternary operator

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

Answers (4)

Scratte
Scratte

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

itwasntme
itwasntme

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

Ryuzaki L
Ryuzaki L

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

stringy05
stringy05

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

Related Questions