4 ms·
Given that the entire constructor call stack is known at compile time, it should be possible to use static analysis to detect if fields are used before initiali
by rcme 4y ago
Given that the entire constructor call stack is known at compile time, it should be possible to use static analysis to detect if fields are used before initialization. Swift does this, I believe.
- layer8 4y agoYou can call methods from constructors, including methods overridden in unknown subclasses, or methods in superclasses whose implementation may change later, which complicates things. You can also pass this to foreign code from a constructor, which in turn may call arbitrary methods and/or access fields on the instance.
- georgelyon 4y agoThe way Swift handles this is that you can’t do anything that involves the self pointer before calling super.
- rcme 4y agoSure, the super class can call unknown methods in subclasses in its constructor, but the subclass has knowledge of the super class, so the subclass should fail to compile if it overrides a super class method that access instance variables before they’re initialized.
- layer8 4y agoSuperclass implementations can change later (you can recompile the superclass without having to recompile the subclass), you can’t assume their current implementation will stay the same.
- rcme 4y agoYou could also remove a method from the superclass entirely in such a situation. This would cause an invocation of the removed method to fail if the subclass depended on it. In general you need to recompile the subclass if the superclass changes.
- layer8 4y ago> In general you need to recompile the subclass if the superclass changes. This just isn’t true. There are compatible changes and incompatible changes you can make. Having the soundness of the compiler rely on the assumption that there won’t be any changes just isn’t viable. For example, the thread-safety guarantees provided by final fields would be difficult to ensure.
- rcme 4y ago> This just isn’t true. There are compatible changes and incompatible changes you can make. This statement exactly applies to the case you mentioned: Superclass implementations can change later (you can recompile the superclass without having to recompile the subclass), you can’t assume their current implementation will stay the same.
- layer8 4y agoFor me these are on two different levels. The guarantees about final fields being assigned exactly once, and the related thread-safety guarantees, are part of the soundness of the language. Late binding may fail and you'll get a NoSuchMethodError or similar, that's fine. But you won't get an Error thrown if suddenly your fields fail to initialize or your class stops being thread-safe just because the superclass implementation changed.
- tsimionescu 4y ago> In general you need to recompile the subclass if the superclass changes. If you are using "in general" in the sense of "in the general case", you are right. But if you are using it as "typically", then that's not true - it's very common for example for a library to be compiled with Java X while subclassing at least a few standard library classes, and then to keep using the same compiled classes with Java X+1, X+2, and to expect them to just work. The Java Standard Library actually takes quite a bit of care to make sure modifications to its (non-final) classes are backwards compatible even for subclasses.
- pron 4y agoJava supports separate compilation and binary compatibility, so any class needs to be compilable without knowing anything about any other class other than its signatures, and cannot depend on knowledge about code inside methods.
- rcme 4y agoSure, but it’s up to the user to ensure that a compatible implementation is available at runtime. And generally people don’t compile against the interface. They compile with the implementation present. Just as you get a runtime exception if you invoke a missing method, you could get a runtime exception for accessing uninitialized state.
- tsimionescu 4y agoJava supports dynamic libraries. As long as the API hasn't changed, your class may be initialized using a different version of its superclasses than it had when it was compiled, so checking statically is not that valuable. And this is not just a theoretical possibility, it's quite common for Java libraries to be distributed in bytecode format, and to be run on various versions of the JVM - so at least any library which subclasses any standard library class is going to often run with various versions of its superclass.