Search code examples
javabinary-operatorsconditional-execution

Why does Java not optimize |= assignments?


t*() always returns true for this example, where as f*() always returns false.

Let's say we have the following expression

if ( f1() || t1() || f2() || t2() ){
    // do stuff        
}

If this is the case the JVM optimizes the execution and only executes f1() and t1() because it 'understands' that no matter what f2() and t2() yield, the requirement for entering the if-statement is fulfilled and therefor no further calculations are required.

I'm working on a code where I wrote something like this:

boolean b = false;
b |= f1(); // A
b |= t1(); // B
b |= f2(); // C
b |= t2(); // D

One of my colleagues saw this and mentioned that he is not sure, but it could be possible that Java optimizes the statements C and D, because b is always true from statement B onward and this could lead to some issues.

I conducted some tests, it seems as if all of them are properly executed (this is the desired behavior), but I'm still wondering why doesn't this get optimized? I figured he might be right and the JVM understands that once b is true no |= operation on it will change its value.


Solution

  • I'm still wondering why doesn't this get optimized?

    Because that would be a violation of the JLS.

    The statement

    b |= f1();
    

    is equivalent to

    b = (boolean)(b | f1());
    

    In the above, the JLS requires that b | f1() is evaluated as follows:

    1. Get the value of b.
    2. Call f1() and capture the resulting value
    3. Apply the | operator to the two values.

    The JLS does not allow the compiler to skip the call f1() if b is true1.

    If you want that semantic (short-circuiting), you need to use b = b || f1(); and so on. (As you noted: b ||= f1() is a syntax error.)


    1 - Actually, in a situation where it was not possible to observe (in a single-threaded program) that an f1() call had or had not happened, the optimization would in theory be permissible. But you would only to be able to detect the optimization by carefully examining the native code emitted by the JIT compiler. It it could only happen if the call was strictly side-effect free.