I made a couple of versioning mistakes recently when moving my development environment from one computer to another (and to another). This basically resulted in me sending a 1.6-only binary to a QA team (read: my boss) with a 1.5 JVM. I decided that the best way to solve it was to move my development environment to 1.5, and just use 1.6 to run applets and ordinary programs (such as IDEA). I was already using -source 1.5 in my ant file, but I had forgotten to tell IDEA about that.. When I downgraded, I recompiled, and found a very amusing compiler bug in the latest release of Java 5. A bit of background: I've never liked the usual workaround for the 'final' restriction on local variables accessed from within a local class, i.e., the single-element array. Hopefully it will go away with Java 7. So, I made a Var class. It used to be all fake-OO, it would have a set and a get, a bit like Shai Almog's amusing properties proposal. Since upgrading to 1.6, I decided that as I did no validation with a Var, I may as well expose its value directly. public final class Var<T> { public T value; public Var(T value) { this.value=value; } } The Java 5 compiler was crashing on var.value++ within local classes. I had to change those to var.value=var.value+1. I wonder how that manages to be fixed in Java 6, but fails consistently with Java 5 versions (I've seen it once before, but didn't bother to debug it at the time, as I was mid-refactor). I'm not sure it's even worth reporting as a bug, because somebody must have fixed it for Java 6, and made a conscious decision not to bother for Java 5. Or so I assume. Perhaps the Java compiler is trying to force me to use encapsulation. Personally, I prefer one of Lisp's styles of encapsulation - don't even make the attribute that you're concerned about be a part of the object (e.g., (let ((x 5)) (defun inc () (incf x 5))), assuming I've got that right), but we can't do that, so I just make it public until there's a reason not to.
CodeSOD: Magical Bytes
8 hours ago
9 comments:
Is this also related to autoboxing?
I expect so. I only noticed it on Var<Integer>s.
You certainly CAN hide things by not making them part of the object. Do that by making the implementation class an inner class, and placing the state into the enclosing class. If the state variables are final, you can also use a local class and place the state in local variables.
Or use closures.
Unfortunately, it takes quite an amount of paperwork to backport a compiler fix to an update release. So until we can streamline that process, I decided to focus my energy on JDK 6 believing that 10X bug fixes in JDK 6 is better than X bug fixes in update releases.
Neal, understood, and when I'm programming to interfaces, I almost always do that for final variables. For non-final variables, they still have to be part of an object, or be accessed through hacks like single-element arrays, or my Var class, though that's not such a serious problem.
Indeed, closures should fix this.
Can you, reflectively, without a security manager, get at those final fields, or the enclosing 'this' member, as they are generated as synthetic fields in the inner class?
Peter, it's interesting that backporting fixes is so awkward.
Hi Ricky,
I replied to your comment about Generics on my blog. Thanks for reading and commenting!
You mean it actually crashes? Then you should definitely support it. The fact that it no longer occurs in java6 doesn't mean it was explicitly discovered, fixed and consciously not backported. It may as well have been covered up implicitly by another fix.
I had a similar bug (in all Java versions) with an inner class failing to access outer class values at runtime, no compiler warning at all!!
I ended up having to provide accessor methods or pass values in via constructors or methods.
Wouter, Peter von der Ahé, the guy who fixed it, commented above that he decided not to backport it.
Anonymous, have you got a test case for that failure? I have no problems in the area you describe.
Post a Comment