Search code examples
javaperformancecompilation

Does the order of method declarations in a Java class lead to faster compilation?


I have a very large Java project with lots of classes and methods.

I read on Wikipedia that "Languages like Java require a multi-pass compiler since the definition of x would not be required to come before the use". If I structured the code using / rules so that all methods in a class are declared before they are used in the class's code, would this speed up the compilation process (vs all methods defined after they are used) because it would not have to do the additional passes during compilation? If true, would it also speed up compilation if only some of the methods were defined in the code before they were used (vs all methods defined after they are used)?

I understand that readability/maintenance should come first, but only consider the performance implications for my question.


Solution

  • In short, no, there is no benefit to expect.

    Java compilers do not even try to perform single-pass processing, so it doesn’t matter whether your code arrangement would allow it.

    The C programming language only has global functions which makes it easy to reason about the set of defined functions at a particular code location.

    In contrast, Java has no global functions at all. The context specific resolution includes methods declared in the same class as the caller (the ones you have in mind), methods inherited from a super class or interface, methods declared in an outer class, methods inherited by an outer class, and methods resolved through an import static statement.

    Further, unlike C, Java supports method overloading. Therefore, for resolving a method, it is not enough to find an applicable method, the Java language requires the compiler to find the most specific method. So even if there’s a matching method declaration right above the caller, the compiler has to check whether there’s a more specific method below the caller or inherited from the superclass.

    In other words, the case that an invocation resolves to a most specific method immediately preceding the invocation in the same source file is a rare corner case, no compiler vendor will try to optimize.

    While details are implementation dependent you can expect the processing to be basically as described on the Wikipedia article you’ve linked in the question. First, an abstract syntax tree is built during the syntactic analysis, then, semantic analysis and code generation will operate on that data structure. A single pass would have to work differently, hence, require maintaining an alternative implementation for no benefit as it would not work for real life cases.


    To illustrate the requirements on the semantic analysis happening after the syntactic analysis a bit more, consider the following example:

    System.out.println("hello world");
    

    While the purpose of this statement is obvious to the reader, it is not to the compiler:

    • There could be a variable System whose type has a member variable out whose type has a println method.
    • There could be a variable System whose type has an inner class out with a static println method.
    • There could be a type System having a static member variable out whose type has a println method. (Bingo)
    • There could be a type System having a nested class out with a static println method.
    • There could be a type System.out having a static println method.

    Since variables have precedence over types which have precedence over packages, the compiler has to check in above order. In other words, even this idiomatic print statement requires processing the entire class declaration, to check whether there’s a variable named System in scope (which includes inherited member variables). Even if not, the compiler also has to check for a class System in the local and nested scopes, as well as in the current package, as the class implicitly imported from java.lang has the lowest precedence.

    So, not even a hello-world example would allow compiling in a single pass.