9.2 Elaboration Order

The sequence by which the elaboration code of all units within a partition is executed is referred to as ‘elaboration order’.

Within a single unit, elaboration code is executed in sequential order.

package body Client is
   Result : ... := Server.Func;

   procedure Proc is
      package Inst is new Server.Gen;
      Inst.Eval (Result);
   end Proc;
end Client;

In the example above, the elaboration order within package body Client is as follows:

  1. The object declaration of Result is elaborated.
    • Function Server.Func is invoked.
  2. The subprogram body of Proc is elaborated.
  3. Procedure Proc is invoked.
    • Generic unit Server.Gen is instantiated as Inst.
    • Instance Inst is elaborated.
    • Procedure Inst.Eval is invoked.

The elaboration order of all units within a partition depends on the following factors:

A program may have several elaboration orders depending on its structure.

package Server is
   function Func (Index : Integer) return Integer;
end Server;
package body Server is
   Results : array (1 .. 5) of Integer := (1, 2, 3, 4, 5);

   function Func (Index : Integer) return Integer is
      return Results (Index);
   end Func;
end Server;
with Server;
package Client is
   Val : constant Integer := Server.Func (3);
end Client;
with Client;
procedure Main is begin null; end Main;

The following elaboration order exhibits a fundamental problem referred to as ‘access-before-elaboration’ or simply ‘ABE’.

spec of Server
spec of Client
body of Server
body of Main

The elaboration of Server’s spec materializes function Func, making it callable. The elaboration of Client’s spec elaborates the declaration of Val. This invokes function Server.Func, however the body of Server.Func has not been elaborated yet because Server’s body comes after Client’s spec in the elaboration order. As a result, the value of constant Val is now undefined.

Without any guarantees from the language, an undetected ABE problem may hinder proper initialization of data, which in turn may lead to undefined behavior at run time. To prevent such ABE problems, Ada employs dynamic checks in the same vein as index or null exclusion checks. A failed ABE check raises exception Program_Error.

The following elaboration order avoids the ABE problem and the program can be successfully elaborated.

spec of Server
body of Server
spec of Client
body of Main

Ada states that a total elaboration order must exist, but it does not define what this order is. A compiler is thus tasked with choosing a suitable elaboration order which satisfies the dependencies imposed by ‘with’ clauses, unit categorization, elaboration-control pragmas, and invocations performed in elaboration code. Ideally an order that avoids ABE problems should be chosen, however a compiler may not always find such an order due to complications with respect to control and data flow.