Ada: Packages
A package is Ada's unit of modularization: a specification that states what it offers, and a body that implements it. Clients compile against the specification alone, so the implementation can change — even completely — without recompiling a single client. This is the chapter the whole language is organized around.
Spec and Body
Two files, two roles. The specification (.ads) is the contract; the body (.adb) is the implementation:
-- geometry.ads — the specification: what clients see
package Geometry is
type Square is private; -- hidden internals
function Make (Side : Float) return Square;
function Area (S : Square) return Float;
private
type Square is record Side : Float; end record; -- visible to children only
end Geometry;
-- geometry.adb — the body: how it works
package body Geometry is
function Make (Side : Float) return Square is
((Side => Side)); -- record aggregate as a body
function Area (S : Square) return Float is
(S.Side * S.Side);
begin
null; -- optional elaboration code runs once at start-up
end Geometry;
Using a Package
A client names the package with with and may use it to drop the prefix. Every reference is still resolved at compile time — there is no dynamic dispatch hiding here:
with Geometry; -- name the dependency
-- with Geometry; use Geometry; -- with use: Area (S) instead of Geometry.Area (S)
procedure Client is
S : Geometry.Square := Geometry.Make (2.0);
begin
null; -- Geometry.Area (S) = 4.0
end Client;
Style note: many teams reserve use for operators and enumeration literals, keeping type names prefixed — it makes provenance obvious at every call site.
Private Types
type Square is private; declares a type whose clients know exists but cannot inspect or construct directly. The full declaration appears under private in the same spec. This is Ada's encapsulation workhorse:
- Clients can declare
Squarevariables, assign, and compare them — but not read or writeSidedirectly. - The only way in is through the package's functions:
Makecan enforce invariants (side > 0) that every object satisfies. - Change the record to hold a diagonal instead — no client recompiles, because nothing in the visible part changed.
Child Packages
Large units grow as children: Geometry.Shapes lives in its own spec/body pair, has full access to Geometry's private part, and adds capabilities without touching the parent:
-- geometry-shapes.ads
package Geometry.Shapes is
function Perimeter (S : Geometry.Square) return Float;
end Geometry.Shapes;
Children solve the "library extension" problem: the standard library is built this way (Ada.Text_IO is a child of Ada), and your own hierarchies will use the same pattern. Next: Exceptions.