use Clauses, Renaming & Elaboration
Control visibility with use, use type and use all type clauses (and their scope), resolve name clashes, rename packages, subprograms and objects, and understand elaboration order, Pure / Preelaborate / Elaborate_Body, and pragma Elaborate_All.
Ada gives you precise control over which names are directly visible. The use clause saves typing but can hide where names come from; use type imports just operators; renaming creates short, meaningful aliases without copying. Finally, elaboration — the run-time 'initialization' of library units before the main program — follows rules that you can make explicit and safe with a few aspects and pragmas.
use, use type, use all type
'use Pkg;' makes all of Pkg's visible declarations directly visible. It can appear in a context clause (whole unit) or inside any declarative part, where its effect is limited to that region — prefer the narrowest scope. 'use type Pkg.T;' makes only the operators of T directly visible, the common compromise: A + B works but other names still need prefixes. 'use all type Pkg.T;' also makes T's primitive subprograms and enumeration literals visible. A use clause never hides a local declaration; if two used packages declare the same name and the context cannot disambiguate, the reference is ambiguous and you must use an expanded name.
• use Pkg; — everything; limit its scope. • use type Pkg.T; — only operators of T. • use all type Pkg.T; — operators + primitives + literals. • Clashes → ambiguity error; qualify with Pkg.Name.
Renaming
Renaming declarations create a new name for an existing entity: 'package IO renames Ada.Text_IO;', 'procedure Say (S : String) renames IO.Put_Line;', 'function Feet (M : Meters) return Float renames Units.To_Feet;', and object renaming 'Second_X : Integer renames Points (2).X;' — an alias to the same storage (assigning Second_X changes Points (2).X). Object renaming is excellent for naming a deeply nested component once. A subprogram declaration can also be completed by a renaming-as-body.
• package P renames Long.Package.Name; • procedure / function ... renames Other; • X : T renames Some.Component; — alias, no copy.
Elaboration
Before the main program runs, every library unit is elaborated: declarations are evaluated and package body statements execute. The binder chooses an order consistent with dependencies, but a problem arises when a unit calls into or reads another unit whose body has not yet been elaborated (calling it raises Program_Error — 'access before elaboration'). Tools to control this: aspect Pure (no state; can elaborate anytime), Preelaborate (no elaboration code needed), Elaborate_Body (elaborate the body immediately after the spec), and in clients pragma Elaborate (Unit) / Elaborate_All (Unit) (elaborate that unit and its dependencies first). GNAT's default static elaboration model checks most of this at compile/bind time.
Without 'with Elaborate_Body' on Config's specification, GNAT warned when compiling this lesson's example: 'variable "Start_Value" can be accessed by clients before this initialization' and suggested 'add pragma "Elaborate_Body" to spec "Config" to ensure proper initialization'. Adding the aspect removed the warning.
• Elaboration = running unit initialization before main. • Access before elaboration → Program_Error. • Pure, Preelaborate, Elaborate_Body (spec aspects); Elaborate / Elaborate_All (client pragmas).
Code Examples
Config is elaborated before the main program; use type makes Meters' "+" usable; Say and Feet are subprogram renamings; Second_X aliases Points (2).X; a block-local use clause makes the unbounded-string operations visible. Output: [Config elaborated] Start_Value = 42 D + D = 3.00000E+00 Twice = 3.00000E+00, in feet: 4.92126E+00 Points (2).X = 30 Ada 2022 (length 8)
Two used packages both define Red. Real GNAT diagnostics: l29_err.adb:13:11: error: ambiguous operands for equality l29_err.adb:13:11: error: use -gnatf switch for details Fix: write Colors.Red or Traffic.Red (or qualify: Colors.Color'(Red)).
with A, B, C, D; use A, B, C, D; -- everything visible everywhere with A, B, C, D; use type A.Money; -- only what is needed, as locally as possible
Broad use clauses obscure where names come from and invite ambiguities.
Tmp : Integer := Points (2).X; Tmp := 30; -- expecting Points to change
Tmp : Integer renames Points (2).X; Tmp := 30;
An initialized variable is a copy; a renaming is an alias.
-- package body reading another package's variable during elaboration, no pragma pragma Elaborate_All (Other); -- or make Other Preelaborate/Pure
Make elaboration dependencies explicit to avoid Program_Error at startup.
Which clause makes only the operators of a type directly visible? A. use Pkg; B. use type Pkg.T; C. use all type Pkg.T; D. with Pkg;
After 'X: Integer renames A (3);' and 'X:= 5;', what is A (3)? A. Unchanged B. 5 C. Compile error D. Undefined B. 5 — renaming creates an alias.
What exception signals access before elaboration? A. Constraint_Error B. Program_Error C. Storage_Error D. Tasking_Error
Which aspect states that a package has no state and can be elaborated anywhere? A. Pure B. Inline C. Volatile D. Pack Trace the program.
Real output: [Config elaborated] Start_Value = 42 D + D = 3.00000E+00 Twice = 3.00000E+00, in feet: 4.92126E+00 Points (2).X = 30 Ada 2022 (length 8)
-- file: config.ads
package Config
with Elaborate_Body -- body is elaborated right after the spec
is
Start_Value : Integer; -- initialized in the body's elaboration
function Describe return String;
end Config;
-- file: units.ads
package Units
with Pure -- no state, no side effects: can be elaborated anywhere
is
type Meters is new Float;
function "+" (L, R : Meters) return Meters is (Meters (Float (L) + Float (R)));
function Twice (M : Meters) return Meters is (M + M);
function To_Feet (M : Meters) return Float is (Float (M) * 3.280_84);
end Units;
-- file: config.adb
with Ada.Text_IO;
package body Config is
function Describe return String is ("Start_Value =" & Integer'Image (Start_Value));
begin
Start_Value := 40 + 2;
Ada.Text_IO.Put_Line ("[Config elaborated]");
end Config;
-- file: l29_use_rename.adb
with Ada.Text_IO;
with Ada.Strings.Unbounded;
with Units;
with Config;
pragma Elaborate_All (Config); -- ensure Config (and its dependencies) are elaborated first
procedure L29_Use_Rename is
-- Package renaming: a short alias
package IO renames Ada.Text_IO;
package SU renames Ada.Strings.Unbounded;
-- use ty
…with Ada.Text_IO; use Ada.Text_IO;
procedure L29_Err is
package Colors is
type Color is (Red, Green);
end Colors;
package Traffic is
type Signal is (Red, Amber, Green);
end Traffic;
use Colors, Traffic;
X : Integer := 0;
begin
if Red = Red then -- which Red?
X := 1;
end if;
Put_Line (Integer'Image (X));
end L29_Err;