Or, proof by example that C# isn’t just Java with different capitalization conventions.
On the heels of Neal Gafter’s ice cream puzzler we have the less closure-rific but still interesting “Why do initializers run in the opposite order as constructors?” from Eric Lippert. Here’s my Java version of Eric’s C# code:
class Foo { public Foo(String s) { System.out.printf("Foo constructor: %1$sn", s); } } class Base { private final Foo baseFoo = new Foo("Base initializer"); public Base() { System.out.println("Base constructor"); } } class Derived extends Base { private final Foo derivedFoo = new Foo("Derived initializer"); public Derived() { System.out.println("Derived constructor"); } } class Program { public static void main(String[] args) { new Derived(); } }
I’ll spare you the suspense and just print the answer — the Java answer, that is.
Foo constructor: Base initializer Base constructor Foo constructor: Derived initializer Derived constructor
Whereas the C# code equivalent of the above, Eric’s original, prints:
Foo constructor: Derived initializer Foo constructor: Base initializer Base constructor Derived constructor
What’s going on?
The Java code does this because when a Java object’s initialized the JVM works its way down through its superclasses, starting at the root (that is, Object
), and for each class first runs the initializers, then the constructor. This can have some wacky side-effects. For instance, sooner or later everyone gets the bright idea to define an abstract method in the base class and call that method from the base class constructor — which works fine until some subclass’s concrete implementation depends on a field that’s only initialized in that subclass, and suddenly you’re getting NullPointerException
s in impossible-looking places.
This happens whether the field’s initialized in the subclass constructor or in a subclass initializer, and while it’s fairly obvious what’s going on in the constructor case, it’s a little more confusing the first time you have, say,
private final long timestamp = new Date().getTime()
come out 0
(or null
, if you use a capital-L Long
) when you know your clock’s not set to January 1st 1970 — and then later on come out 1203338390828
or whatever, even though final
fields are supposed to be immutable.
The constructor case, I think we’re stuck with. The initializer case, though, the folks at Microsoft apparently decided they were sick of. So C# instead runs all the initializers in reverse order (subclass to superclass), and then runs all the constructors (in the order you’d expect). This means final
fields in C# really are final, or rather, readonly
fields really are read-only — they’ll only ever have one value, no matter when you look at them. [Looks like I didn’t have that quite right — see Eric’s comment below.]
Now I wonder what happens in ActionScript? The Adobe folks claim my const
bug in FlexBuilder is fixed; I’ll have to download the latest build and see.
Comments closed due to spam.
Hey David,
Your conclusion that a readonly field may ever have only one value is not correct. The actual rules for a readonly field are:
* The readonly field begins its life with its default value.
* A readonly field may be assigned a value any number of times, but only by a constructor.
(Of course, it is a terrible programming practice to assign to a readonly field multiple times in a constructor, but it is legal.)
The correct conclusion to make from these facts is:
* if you assign a value to a readonly field in the field initializer, AND
* there are no assignments to the field in any constructor, THEN
* the field can only ever be observed to have its final value.
That’s why it is a best practice to assign to the field in an initializer if possible. Of course, it is not always possible; sometimes the value is going to depend upon arguments passed to the constructor.
Interesting — thanks for the correction. I suppose that’s convenient when you’re extending some class and the original author didn’t necessarily expect you to need the field to take on a different value.