Tuesday, 9 March 2010

JavaFX initialisation order (solved?)

The semantics of JavaFX's initialisation order can be hard to find, and in a previous post, I was finding it gave some odd effects. Having looked on the JavaFX bug tracker, it turns out it the issue is fairly simple, but needs trumpeting from the hills because it is still unexpected.

B.one will be null. How is that possible? Because of what override means -- it changes the definition but not the "order of declaration".

A naive person might think that B.one would first be set to 1 (in the initialisation of A) and then to 2 (in the initialisation of B). Or they might think that B.two will be set before B.one because it comes first in B's script. But that's not how JavaFX does it. The variable one is initialised first because it is declared first (in A's class declaration, which comes before B's.) But it is set to B.two because only the override initialiser takes place. Unfortunately, this means it is set to B.two before B.two has actually been defined -- so it gets set to null.

The moral of the story: Don't use override var if you want to set the variable to refer to another member variable. It's a forward reference. Even if the member variable you want to refernce also comes from a superclass, it could still be a forward reference (because you don't know what the order of declaration was in the superclass).

If in doubt, set it in the init block. That always happens in the order that you specify in the block, after everything else has happened. It's boring and more Java-like, but at least you can even step through it with a debugger and put log messages in if you need to!

No comments: