The previous section discussed the case in which the execution of a particular thread of elaboration code occurred entirely within a single unit. This is the easy case to handle, because a programmer has direct and total control over the order of elaboration, and furthermore, checks need only be generated in cases which are rare and which the compiler can easily detect. The situation is more complex when separate compilation is taken into account. Consider the following:
package Math is function Sqrt (Arg : Float) return Float; end Math; package body Math is function Sqrt (Arg : Float) return Float is begin ... end Sqrt; end Math; with Math; package Stuff is X : Float := Math.Sqrt (0.5); end Stuff; with Stuff; procedure Main is begin ... end Main;
where Main is the main program. When this program is executed, the elaboration code must first be executed, and one of the jobs of the binder is to determine the order in which the units of a program are to be elaborated. In this case we have four units the spec and body of Math, the spec of Stuff and the body of Main), and the question is in what order should the four separate sections of elaboration code be executed?
There are some restrictions in the order of elaboration that the binder can choose. In particular, if you have a with for a package X, then you are assured that the spec of X is elaborated before you are, but you are not assured that the body of X is elaborated before you are. This means that in the above case, the binder is allowed to choose the order:
but that's not good, because now the call to Math.Sqrt that happens during the elaboration of the Stuff spec happens before the body of Math.Sqrt is elaborated, and hence causes Program_Error exception to be raised. At first glance, one might react that the binder is being silly, because obviously you want to elaborate the body of something you with first, but that is not a general rule that can be followed in all cases. Consider this:
This is a common arrangement, and, apart from the order of elaboration problems that arise only in connection with elaboration code, works fine. A rule that says that you must elaborate the body first of anything you with cannot work in this case (the body of X with's Y, which means you want to elaborate the body of Y first, but that with's X, which means you want to elaborate the body of X first, but ... and we have a loop that cannot be broken.
It is true that the binder can in many cases guess an order of elaboration that is unlikely to cause a Program_Error exception to be raised, and it tries to do so (in the above example of Math/Stuff/Spec, the XGC Ada binder will in fact always elaborate the body of Math right after its spec, so all will be well).
However, a program that blindly relies on the binder to be kind can get into trouble, as we discussed in the previous sections, so XGC Ada provides a number of facilities for assisting the programmer in developing programs that are robust with respect to elaboration order.