Assertions in java compile down to a private synthetic static boolean added to a test - the proposal is nicely documented here:
JSR Assertion Proposal
In it, we create
final private static boolean $assertionsEnabled = ClassLoader.desiredAssertionStatus(className);
and then
assert(X)becomes
if ($assertionsEnabled && !x) { throw }
Which makes perfect sense ;)
However, I've noticed that what I actually get is
public void test1(String s) {
assert (!s.equals("Fred"));
System.out.println(s);
}
becomes
static final /* synthetic */ boolean $assertionsDisabled;
public void test1(String s) {
if ((!(AssertTest.$assertionsDisabled)) && (s.equals("Fred"))) {
throw new AssertionError();
}
System.out.println(s);
}
static {
AssertTest.$assertionsDisabled = !(AssertTest.class.desiredAssertionStatus());
}
I can't find any documentation as to why they went with a NEGATIVE test, rather than a positive test - i.e. the original proposal captured assertionsENABLED, now we use assertionsDISABLED.
The only thing I can think of is that this would possibly (POSSIBLY!) generate better branch prediction, but that seems like a pretty lame guess to me - the Java philosophy is (almost) always to make the bytecode simple, and let the JIT sort out optimisations.
( note that this isn't a question about how assertions work - I know that! :) )
( As an aside, it's quite interesting to see that this leads to incorrect tutorials! 6.2.1 of this tutorial, which someone quoted in response to a previous SO question on assertions gets the sense of the test wrong! :)
Any ideas?
This is actually done for a reason, not merely for something like a more compact bytecode or faster condition execution. If you look at the Java Language Specification, §14.10, you will see the following note:
An assert statement that is executed before its class or interface has completed initialization is enabled.
There's also an example that contains an initialization loop:
class Bar {
static {
Baz.testAsserts();
// Will execute before Baz is initialized!
}
}
class Baz extends Bar {
static void testAsserts() {
boolean enabled = false;
assert enabled = true;
System.out.println("Asserts " +
(enabled ? "enabled" : "disabled"));
}
}
As Bar
is a superclass for Baz
, it must be initialized before Baz
initialization. However, its initializer executes an assertion statement in the context of Baz
class that is not initialized yet, so there was no chance to set the $assertionsDisabled
field. In this case, the field has its default value, and everything works according to the spec: assertion is executed. Had we have an $assertionsEnabled
field, the assertions for an uninitialized class would not be executed, so it would violate the specification.
The boolean is actually implemented with an integer. There is a common believe that comparison with zero is quicker, but I don't see any reason to use disable instead of enabled.
IMHO, as false is the default for boolean, I try to chose a flag which has a default value of false
In this case $assertionsEnabled
would make more sense.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With