Ada: Visibility

Visibility rules decide which names a region of code can see. Ada's are stricter than most languages: nothing is imported implicitly, name clashes are compile errors, and every widening of scope is a written use or renames. This page gives you the working set.

with and use

with makes a library visible — its name only. use additionally makes its contents directly visible, dropping the package prefix:

with Ada.Text_IO;                 -- Ada.Text_IO.Put_Line is visible
--  with Ada.Text_IO; use Ada.Text_IO;   -- Put_Line is visible directly

procedure Visibility_Demo is
begin
   Ada.Text_IO.Put_Line ("explicit — always safe");
   --  Put_Line ("direct — requires use");
end Visibility_Demo;

Ada has no namespace glob beyond the unit you name: use applies to one package, one clause at a time. Name clashes from two used packages are compile errors, forcing you to resolve them explicitly.

Common style: with always; use freely for small utility packages (Ada.Text_IO), sparingly for large ones.

use type

Sometimes you want the operators of a package's types but not every name. use type imports only operator visibility — the idiomatic middle ground:

with Ada.Strings.Unbounded;

procedure Use_Type_Demo is
   use type Ada.Strings.Unbounded.Unbounded_String;   -- operators only

   A : Ada.Strings.Unbounded.Unbounded_String :=
      Ada.Strings.Unbounded.To_Unbounded_String ("a");
begin
   A := A & "b";            -- & is now directly visible
   null;
end Use_Type_Demo;

renames

renames gives an existing entity a new local name — a spelling shortcut, never a new object:

with Ada.Text_IO; use Ada.Text_IO;

procedure Renames_Demo is
   procedure Log (S : String) renames Put_Line;   -- a local alias
   package TIO renames Ada.Text_IO;               -- a package alias

begin
   Log ("compact call site");
   TIO.New_Line;
end Renames_Demo;

Renames shine in big subsystems: rename a deep library once at the top of a file and the rest of the file reads cleanly, while the dependency stays explicit at the top.

Nesting and Scope

Names are visible from their declaration to the end of the enclosing region. Inner declarations shadow outer ones — and GNAT warns about the shadowing, because it is usually accidental:

procedure Shadow_Demo is
   Count : Integer := 1;
begin
   declare
      Count : Integer := 2;   -- shadows the outer Count for this block only
   begin
      null;   -- here Count is 2
   end;
   null;      -- here Count is 1 again
end Shadow_Demo;

Package bodies, task bodies, and exception handlers each form their own declarative regions with the same rule. When you deliberately want a nested helper subprogram, declare it in the body's declarative part — it is invisible outside, which is exactly what you want:

procedure Helper_Demo is
   --  Helper is private to Helper_Demo: no other unit can call it
   function Helper (X : Integer) return Integer is (X * 2);
begin
   null;   -- Helper (21) = 42
end Helper_Demo;

Next: OOP — the last paradigm layer.