|M.Sc Thesis||Department of Computer Science|
|Supervisor:||Assoc. Prof. Gil Joseph|
|Full Thesis text|
Most OO languages abide by the semantics that the constructor of a derived class is a refining extension of one of the base class's constructors. As this base constructor computes, it may invoke dynamically bound methods which are overridden in the derived class. When such methods are invoked, they receive a "half baked object", i.e., an object whose derived class portion is uninitialized. Such a situation may lead to confusing semantics and complicated coupling between the base and the derived classes. Further, this possibility makes it difficult to introduce mechanisms for expressing design intent within the programming language, and to develop automatic tools for the checking of these. Prime examples include: non-null annotation (denoting reference values which can never be null), read-only annotation for fields and variables (expressing the intention that these cannot be modified after they are completely created) and class invariants (part of the "design by contract" methodology). A read-only field, for example, becomes immutable only after the creation of the enclosing object is complete.
This work is an empirical investigation of the current programming practice in Java of calling dynamically bound methods inside constructors. In a data set comprising a dozen software collections with over sixty thousand classes, we found that although the potential for such a situation is non negligible (with prevalence over 8%), i.e., there are many constructors that make calls to methods which may be overridden in derived classes, this potential is realized scarcely. We found this behavior in less than 1.5% of all constructors, inheriting from less than 0.5% of all constructors. Further, we found that over 80% of these incidents fall into eight "patterns", which can be relatively easily transformed into equivalent code which does not make pre-mature calls to methods.
Another similarly undesirable situation occurs when a constructor exposes the self identity to external code, and this external code chooses to call methods overridden in the derived class. Our estimates on the prevalence of this exposition are less accurate due to the complexity of inter-procedural dataflow analysis.
The resulting estimates are high, but there are indications that this estimation arises from a relatively small number of base constructors.