Saturday, June 28, 2008

Conditional compilation & Conditional loading of a class


Conditional compilation & Conditional loading/initialization of a class

How can one conditionally compile some code in a class?

It's very simple. One possible way is to use a static final boolean variable and assign that variable a value 'false' during declaration. Since it's a final variable, so the compiler knows that the value is not going to change any further. Since the variable is static, so the compiler knows that the variable is a class variable and will remain the same for all the instances.

Now, if we put some code inside a block which tests the value of the static final variable in a conditional statement then the compiler is wise enough to know that the part included inside the conditional statement will never be executed and hence it'll not compile that at all.

Similarly, we may use any such condition which will invariably be false at compile time (or true in which case we may use '!' operator before that expression to convert that into false) to conditionally compile a set of statements put inside a block having that expression as its condition expression. The bottom line is that a Java compiler will NOT compile a block of code which won't be executed.

Unreachable Code vs Non-Compiled Code

Unreachable Code and Non-Compiled Code are completely different. The former results in a compile time error whereas the latter refers to a block of code which is not compiled, but the compilation of the program completes successfully. Don't mix both. Unreachable code refers to a block of code where the control can never reach during execution. For example:- if you write something after an infinite loop then that block will be unreachable as the runtime system will keep running the infinite loop until the stack overflows (or JVM process is terminated by some external interruption). So, Unreachable code is supposed to be a flaw in the program whereas Non-compiled code is something which is not required in the present scenario and hence won't be compiled. So it's kind of compile time optimization.

Example: conditional compilation of a block of code

package test;

public class TestCondCompilation {

public static void main(String[] args) {

TestCondCompilation testCondCompilation = new TestCondCompilatio();
(new CondCompilation()).testMethod();
}

}

class CondCompilation{

public static final boolean COND_COMPILATION = false;

public void testMethod(){

if(COND_COMPILATION){
System.out.println("Never Compiled unless value of COND_COMPILATION is set to true");
}

System.out.println("Compiled");
}

Output:-

Compiled

The above approach can be used to conditionally compile the assertion code in Java. Read more about assertions in this article - Assertions? Assertions vs Exception, Usage, etc. >>. So, this approach can be used effectively to reduce the size of the .class files (by not allowing compilation of assertion code) in case the size is so critical.

Conditional Loading/Initialization of a Class

We can use assertions to implement conditional loading/initialization of class. As we know that assertions can either be enabled or disabled (by default they are disabled), hence we can use that information effectively to achieve this objective.

Example: one popular example of conditional loading/initialization of a class using assertions

class SomeClass{

static{

boolean isAssertionEnabled = false;
assert isAssertionEnabled = true;

if (!isAssertionEnabled)
throw new AssertionError("Class not Loaded as Assertion NOT Enabled!");
}

...
...
}

In the above class we have a static initializer which gets executed first while loading of the class. It first sets a boolean variable isAssertionEnabled to false. The second line simply uses the assert statement which sets the same boolean variable to true. Since, this is an assert statement hence it'll be executed only if the assertion is enabled. So, the boolean variable will continue to have the same value 'false' in case assertion is not enabled. Now, the next if statement checks the value of the boolean variable isAssertionEnabled and it throws an AssertionError object in case the value of the boolean variable is still false (which will be the case only if the assertion is not enabled).

Notice that we can't have an assert statement in place of the 'throw new AssertionError()' as the assert will not be executed in case the assertion is not enabled and if it's enabled then the if statement condition will return false and thus the class will be loaded irrespective of whether assertion is enabled or not. So, it's mandatory to throw AssertionError eplicitily. Of course, we can throw some other Unchecked Exception (like RuntimeException) as well. Can you throw a checked exception like IOException here? Think about it. Not a difficult question ... right?



Share/Save/Bookmark


No comments: