Why does an inline conditional in Java auto-cast numbers?

Go To StackoverFlow.com

5

In the following inline conditionals, one might expect an integer and a double to be printed, respectively:

System.out.println(true ? 0 : 0.0);
System.out.println(false ? 0 : 0.0);
System.out.println(true ? new Integer(0) : new Double(0.0));
System.out.println(true ? 0 : "");

Instead they are both printed as doubles when occurring together:

 0.0
 0.0
 0.0
 0

Why are numbers auto-cast when occurring with other numbers in inline conditionals?

Edit: If this is occurring because System.out.println is overloaded what is the case for:

list.add(true ? 0 : 0.0);
list.add(false ? 0 : 0.0);
list.add(true ? new Integer(0) : new Double(0.0));
list.add(true ? 0 : "");
System.out.println(list);

outputs:

[0.0, 0.0, 0.0, 0]
2012-04-04 18:30
by Garrett Hall


16

Why are numbers auto-cast when occurring with other numbers in inline conditionals?

The conditional expression has to have a single result type, and that type is used to determine which overload of System.out.println to use. Overloads are always determined at compile-time, and it would be really awkward for the compiler to take two completely separate paths for an expression depending on which condition was picked.

If you want to do two different things based on a condition, use an if. If you want to pick between two values, with one result type, based on a condition, then the conditional operator is perfect.

EDIT: The interesting case here, IMO, is the third one. The compiler could have chosen to not perform any conversions, and just call println(Object). To show that it's not doing that, here's a separate test:

Object x = true ? new Integer(0) : new Double(0.0);
System.out.println(x.getClass());

This prints out class java.lang.Double - and if you look at the bytecode, you'll see it's unboxing the int then reboxing it as a Double. For the gory details of how it's all determined, see section 15.25 of the JLS.

2012-04-04 18:33
by Jon Skeet
darn you Jon Skeet! beat me by 5 seconds. I humbly bow.. - Kevin Welker 2012-04-04 18:34
+1 Very interesting edit - Paul Bellora 2012-04-04 18:43
I have a question I bet Jon Skeet doesn't know the answer to. "Is there anything Jon Skeet doesn't know the answer to??" Seriously this is so obscure, and I ....I'm just at a loss for words that you know this off the top of your head - Amir Afghani 2012-04-04 18:44
Thanks for the explanation, but does this also apply to my updated example - Garrett Hall 2012-04-04 18:45
@GarrettHall - This doesn't have to do with System.out.println and whether it has overloads, but that "the conditional expression has to have a single result type" to quote the answer - Paul Bellora 2012-04-04 18:47
Okay, thanks I understand now - Garrett Hall 2012-04-04 18:50
@Amir If you think this is obscure, you really would want to take a look at this - Voo 2012-04-04 18:52


4

Both sides of a conditional operator must be compatible in order to participate in the same ternary operation. According to Java Language Specification 15.25, in your case

binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.

Generally, there is a long list of rules the language follows to arrive at the result type of the ternary conditional operator. Please read the language specifications if you need more details.

2012-04-04 18:37
by dasblinkenlight
@KevinWelker That's exactly the part that I quoted, omitting the irrelevant parts about bytes, shorts, etc - dasblinkenlight 2012-04-04 19:00
oops, sorry, deleted my longish comment to keep this cleane - Kevin Welker 2012-04-04 19:03


0

EDITED Because println is overloaded. It has to resolve to one of the forms, and it chooses the smallest type that captures both (int and double for the 1st 2 examples) : void println(double x)

2012-04-04 18:34
by Kevin Welker
The type of the conditional expression is determined separately from which overload is used. The compiler works out the type of the conditional expression, then determines which overload to pick. In the first three cases the type of the conditional expression is double, so System.out.println(double) is chosen. In the last case, println(Object) is chosen - Jon Skeet 2012-04-04 18:35
Should have said: "I stand corrected. I forgot that "Floating-point literals in Java default to double precision.". Otherwise I was trying to get at the same point, but much less precisely. You are king. - Kevin Welker 2012-04-04 18:53
No, we weren't saying the same thing - because println being overloaded is somewhat irrelevant, as shown by the code in my edit. The results would be the same even if only println(Object) existed - Jon Skeet 2012-04-04 18:57
I was going to add a defense of what was in my head vs my inadequate answer, but now I see that even the inside-my-head answer was inadequate. It has nothing to do with selecting the proper overloaded version, and everything to do with determining the single conditional result before it even bothers looking to see that there are optional overloaded forms of println to resolve. Which was pretty much what you said the first time :- - Kevin Welker 2012-04-04 19:41


0

The common type is used. 0 can be lossless converted to double. The result of (cond) ? res1 : res2 has to be of one return type.

2012-04-04 18:35
by user unknown
Ads