Anatomy of an Ada file
Ada is a strongly typed systems language designed for readability, reliability, real-time work, and high-integrity software; its package specifications commonly use .ads files and bodies use .adb.
File extensions: .adb, .ads
Every part of the example below is labelled and explained. This page is one of 55 annotated tours on AnatomyOf, a free, open-source project by LunarWerx Studios.
What is inside an Ada file
Context clause (`with`)
Makes another library unit available to the current compilation unit.
with Ada.Text_IO; establishes a semantic dependency on the standard text-I/O package. The package name is still qualified unless a separate use clause makes its declarations directly visible. Context clauses sit before the compilation unit they affect. Ada records these dependencies precisely so the build system can compile units in a valid order and recompile dependents when a specification changes.
Use clause
Makes a package’s declarations directly visible without qualification.
use Ada.Text_IO; allows Put_Line in place of Ada.Text_IO.Put_Line. The package must already be available through a with context clause. Many Ada codebases avoid broad use clauses in large scopes because qualification documents where a name comes from. use type is a narrower alternative that makes a type’s primitive operators directly visible without importing every declaration in its package.
Main procedure
A library-level procedure can serve as the program entry point.
procedure Greeter is ... end Greeter; declares and defines a parameterless library unit. The binder selects an eligible library-level procedure as the executable’s main subprogram. Ada conventionally repeats the procedure name after the closing end. The compiler can verify that name, making the end of a long nested unit less ambiguous to a human reader.
Declarative part
Types, objects, constants, and nested subprograms are declared before begin.
The region between is and begin is the subprogram’s declarative part. It establishes every local name and type before executable statements start, so a reader sees the data model and helper operations before control flow. Nested declarations obey lexical scope: Greeting, Say, and Hello exist only inside Greeter. Elaborating the procedure creates or initializes these declarations before its statement sequence runs.
Record type
Combines named, strongly typed components into one composite value.
type Greeting is record ... end record; introduces a distinct composite type. Its components have explicit types and may carry constraints or default expressions. Unlike structural record systems, two separately declared Ada record types are not interchangeable merely because their fields look alike. That nominal typing prevents accidental mixing of values that represent different concepts.
Nested procedure
Defines a reusable operation scoped inside the enclosing procedure.
procedure Say (Item : Greeting) is ... declares a local subprogram. Parameters default to mode in, so Item is an input that the procedure may read but not replace. Ada distinguishes procedures, which do not return a value, from functions, which do. Both may be nested, overloaded, generic, or declared separately from their bodies in a package specification.
For loop and range
Iterates across every value in a discrete range such as 1 .. Item.Times.
An Ada for loop declares its loop parameter implicitly and steps across the supplied range. The parameter is constant within the body and disappears after end loop. Ranges are first-class parts of Ada’s type system, used for loops, array bounds, and scalar constraints. Bounds are checked, turning many indexing and domain mistakes into compile-time diagnostics or defined runtime exceptions.
Named record aggregate
Constructs a record by associating each component name with a value using =>.
(Text => "Hello", Times => 2) is a record aggregate. Named association makes the meaning independent of component order and lets the compiler verify that every required component appears exactly once. Ada also permits positional aggregates, but named aggregates are especially useful in long records because each value explains itself at the construction site.
Statement part
The begin section contains the executable sequence.
The outer begin separates declarations from executable statements. Statements run in order and end with semicolons; structured constructs use explicit closers such as end loop, end if, and end Greeter. Ada favors words over punctuation for control flow. The extra closing labels make nested code more verbose, but they also make its structure hard to misread.
Exception handler
Handles a named failure raised while executing the statement part.
An exception section follows the normal statements. Each when alternative matches an exception; Constraint_Error, for example, covers failed range, index, length, and related language-defined checks. If no handler matches, the exception propagates to the caller. Ada defines the circumstances for its runtime checks rather than treating violations as arbitrary undefined behavior.
Official Ada site · All languages on AnatomyOf
The interactive tour needs JavaScript. Enable it to hover a callout and trace it into the code.