Java constant expressions and code elimination
Asked Answered
O

2

12

As discussed here, javac and other Java compilers may provide code elimination capabilities for if-statements where the condition is a "Constant Expression".

How is this affected if my code uses a constant expression that depends on other constant expressions defined in different packages?

For example, let's say I have the following classes in the respective specified packages:

package foo;

public class Foo {
    public static final boolean CONDITION = false;
}

and

package bar;

import foo.Foo;

public class Bar {
    public void test() {
        if (Foo.CONDITION) {
            System.out.println("This line of code could be eliminated.");
        } else {
            System.out.println("This line of code will be executed.");
        }
    }
}

Clearly, if the foo-package is loaded at run-time from an external jar-file, the compiler can't technically just assume that Foo.CONDITION will be false and should not eliminate the true-branch of the if-statement.

Whereas, if Foo and Bar were actually in the same package, the true-branch should definitely be eliminated (if the compiler supports code elimination at all).

Not quite sure how to best phrase this question, but: How "close" does Foo need to be to Bar for a constant expression in Foo to also be considered constant in Bar? Would they need to be in the same file? the same package? the same jar-file? or does it not matter at all (i.e. would the compiler always consider Foo.CONDITION as constant and use the value found in the build-path during compile time)?

Orbit answered 22/5, 2014 at 21:2 Comment(2)
Try looking at the bytecode with javap -c Bar.Mistletoe
@Mistletoe Indeed, that would allow me to check. But that would just give me one data-point about the behavior of the exact compiler I am using. Is there maybe an actual specification that answers this question? I couldn't find one...Orbit
C
9

Since it's part of the public "signature" of the referenced class, it is assumed to be constant. Essentially the idea is that final means final, and if you change it, it's your fault.

This is similar to actual method signatures of referenced classes, also taken as-is at compile time. Which is why if you compile your code against one version of a library and run it against another, you might get a NoSuchMethodError.

Update: Actually the JLS gives an even stronger guarantee:

If a field is a constant variable (§4.12.4), then deleting the keyword final or changing its value will not break compatibility with pre-existing binaries by causing them not to run, but they will not see any new value for the usage of the field unless they are recompiled. This is true even if the usage itself is not a compile-time constant expression (§15.28).

This result is a side-effect of the decision to support conditional compilation, as discussed at the end of §14.21.

Coletta answered 22/5, 2014 at 21:9 Comment(1)
Perfect! That JLS section answer the question very clearly! Here the actual link to it: docs.oracle.com/javase/specs/jls/se7/html/… (it has some great code examples for clarity) Thanks! √ +1Orbit
H
4

It does not matter how close your constant is. If it is a compile-time constant as defined in the specfication, it will be inlined. Static final (constants) are inlined per Java specification (although I did not find the spec either). This java world article discusses the topic in some detail. The relevant stuff:

According to the Java Language Specification, any static final field initialized with an expression that can be evaluated at compile time must be compiled to byte code that "inlines" the field value. That is, no dynamic link will be present inside class Main telling it to obtain the value for A from InterfaceA at runtime. Instead, the literal 1 will compile into Main.main() directly.

Haldis answered 22/5, 2014 at 21:13 Comment(3)
An interesting side effect of this though is that depending on the expression you're referencing, it may or may not trigger the loading of the referenced class at runtime. Which is somewhat scary.Coletta
That link is very helpful! Thank you! Interesting way to resolve circular dependencies. An error message would have probably been more useful in this case (like Excel does), rather than the somewhat random evaluation-order-dependency. +1Orbit
This one tells an interesting story too about what can happen when multiple libraries (built inconsistently) inline a constant.Haldis

© 2022 - 2024 — McMap. All rights reserved.