Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I found a bug in Java Puzzlers VI - can someone explain it?

Tags:

java

Take a look at this java puzzles vid by Josh Bloch and William Pugh, around time index 0:25:00-0:33:00.

One of the speakers says that if you use lowercase boolean instead of Boolean, then LIVING will be treated as a true "compile time constant", and it no longer matters when it is initialized.

Well, this is all fine and dandy, but, take a look at what happens when you revert to the original order between the static init and the constructor, and then follow it up by a simple "Extract Method" operation. These two programs print different outputs:

public class Elvis {
    private static final Elvis ELVIS = new Elvis();

    private Elvis () {}
    private static final boolean LIVING = true;
    private final boolean alive = LIVING;
    private final boolean lives () {return alive;}

    public static void main(String[] args) {
        System.out.println(ELVIS.lives()); // prints true
    }
}

And with the refactored returnTrue() method

public class Elvis {
    private static final Elvis ELVIS = new Elvis();

    private Elvis () {}
    private static final boolean LIVING = returnTrue();

    private static boolean returnTrue() {
        return true;
    }

    private final boolean alive = LIVING;
    private final boolean lives () {return alive;}

    public static void main(String[] args) {
        System.out.println(ELVIS.lives()); // prints false
    }
}

Why does extracting the returnTrue() method change the program output in this case?

like image 936
ripper234 Avatar asked Jan 05 '11 18:01

ripper234


2 Answers

The key to the behavior that you're observing is notion of "constant variable." This oxymoron is defined in JLS 4.12.4 as a variable of primitive type or type String that is final and initialized with a compile-time constant expression. In JLS 13.1, it says that references to constant fields are resolved at compile time to the constant values they denote (i.e., they're inlined). The puzzle in the video relies on the fact that a Boolean is neither a primitive nor a String. Your variant relies on the fact that invoking a method (returnTrue) in an expression prevents it from being a compile-time constant expression. Either way, LIVING is not a constant variable and the program displays the counterintuitive behavior.

Puzzle 93 in Java Puzzlers ("Class Warfare") is related, and even more surprising.

like image 126
Josh Bloch Avatar answered Nov 07 '22 22:11

Josh Bloch


In the second case LIVING is initialized by the runtime expression, therefore it's not a compile-time constant any more, and its value is false at the time when ELVIS is constructed.

like image 32
axtavt Avatar answered Nov 08 '22 00:11

axtavt