Something you did not know about the ternary operator


Recently I had a little surprise. It started me compiling some Java class and it did not work the way I expected. This is not the surprise itself: this is just the way I live. Develop, debug, release cycles. So the development cycle started. I was looking to find a bug in my code and as I tightened the bug boundary it came down to a ternary operator. The following sample demonstrates the situation:

public class Bug{
    public static Number q(Number in) {
        return in instanceof Long ? 1L : 1.0;
    }
}

It was supposed to return a Long or a Double value of one, depending on the type of the argument. However the method returned a 1.0 Double.

I looked at the code generated by javac using the javap disassembler and I saw that the case is really the one I explained above:

public static java.lang.Number q(java.lang.Number);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0       
         1: instanceof    #2                  // class java/lang/Long
         4: ifeq          11
         7: dconst_1      
         8: goto          12
        11: dconst_1      
        12: invokestatic  #3                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
        15: areturn       

No matter what type the argument has, the code loads a constant Double on the operational stack executing the bytecode (dconst_1). This code is not good. But it does not mean that there is a bug in the javac compiler. This is not a bug, this is a feature.

The next thing I consulted was the Java language specification. You can read it from the URL http://docs.oracle.com/javase/specs/jls/se7/html/index.html and it talks about the ternary operator:

Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:

Otherwise, 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.

In our case numeric promotion happens according to §5.6.2 :

If either operand is of type double, the other is converted to double.

It explains why this code above is useless. in situations like that use the good old ‘if’ ‘then’ ‘else’ construct.

Update

Recently Lukas Eder posted a similar article on his JOOQ blog worth following. This article is brief and highlights a different effect of the same issue.

1 thought on “Something you did not know about the ternary operator

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.