C.2. Checking the Elaboration Order in Ada 95

In some languages that involve the same kind of elaboration problems, e.g. Java and C++, the programmer is expected to worry about these kind of ordering problems himself, and it is quite possible to write a program in which an incorrect elaboration order can give surprising results as a result of referencing variables before they are initialized as intended. Ada 95 is designed to be a safe language, so this approach is clearly not acceptable. Consequently, the language provides three lines of defense:

Standard rules

Some standard rules restrict the possible choice of elaboration order. In particular, if you with a unit, then its spec is always elaborated before the unit doing the with. Similarly, a parent spec is always elaborated before the child spec, and finally a spec is always elaborated before its corresponding body.

Dynamic elaboration checks

Dynamic checks are made at run time, so that if the elaboration order is incorrect, then an exception (Program_Error) is raised.

Elaboration control

Facilities are provided for the programmer to control the order of elaboration to prevent such exceptions from being raised.

Let's look at these facilities in more detail. First, the rules for dynamic checking. One possible rule would be simply to say that the exception is raised if you access a variable which has not yet been elaborated. The trouble with this approach is that it could require expensive checks on every variable reference. Instead Ada 95 has two rules which are a little more restrictive, but easier to check, and easier to state:

Restrictions on calls

A subprogram can only be called at elaboration time if its body has been elaborated. The rules for elaboration above guarantee that the spec of the subprogram has been elaborated before the call, but not the body. If this rule is violated, then the exception Program_Error is raised.

Restrictions on instantiations

A generic unit can only be instantiated if the body of the generic unit has been elaborated. Again, the rules for elaboration above guarantee that the spec of the generic unit has been elaborated before the instantiation, but not the body. if this rule is violated, then the exception Program_Error is raised.

The idea here is that if the body has been elaborated, then any variables it references must have been elaborated, so by checking for the body being elaborated, we are guaranteed that none of its references causes any trouble. As we noted above, this is a little too restrictive, because a subprogram that has no non-local references in its body is in fact safe to call. However, it really would not be right to rely on this, because it would mean that the caller was relying on details of the implementation in the body, which is something we always try to avoid in Ada.

To get an idea of how this might be implemented, consider the following model implementation. A Boolean variable is associated with each subprogram and generic unit. This variable is initially set to False, and is set to True when the body is elaborated. Every call or instantiation checks the variable, and raises Program_Error if the variable is False.