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;