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;
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
the spec of
Stuff and the body of
In what order should the four separate sections of elaboration code
There are some restrictions in the order of elaboration that the binder
can choose. In particular, if unit U has a
for a package
X, then you
are assured that the spec of
is elaborated before U , but you are
not assured that the body of
is elaborated before U.
This means that in the above case, the binder is allowed to choose the
spec of Math spec of Stuff body of Math body of Main
but that's not good, because now the call to
that happens during
the elaboration of the
spec happens before the body of
elaborated, and hence causes
Program_Error exception to be raised.
At first glance, one might say that the binder is misbehaving, because
obviously you want to elaborate the body of something you
that is not a general rule that can be followed in all cases. Consider
|package X is ... package Y is ... with X; package body Y is ... with Y; package body X is ...|
This is a common arrangement, and, apart from the order of elaboration
problems that might arise in connection with elaboration code, this works fine.
A rule that says that you must first elaborate the body of anything you
with cannot work in this case:
the body of
which means you would have to
elaborate the body of
Y first, but that
you have 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
exception to be raised, and it tries to do so (in the
above example of
Math/Stuff/Spec, the GNAT binder will
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 helpful can get into trouble, as we discussed in the previous sections, so GNAT provides a number of facilities for assisting the programmer in developing programs that are robust with respect to elaboration order.