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; begin Inst.Eval (Result); end Proc; begin Proc; end Client;
In the example above, the elaboration order within package body
Server.Genis instantiated as
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 begin 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
Client’s spec in the elaboration order. As a result, the value of
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
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.