Ada

If you’re young, you might not have heard of the Ada language, but you won’t regret learning it.

Overview

Ada was designed in the late 1970s, first released in 1983, and was the first object-oriented language to be internationally standardized (in 1995). The language was designed to facilitate the design of large, long-lived, efficient, reliable software systems. It is particularly useful in concurrent, distributed, real-time, and embedded systems. It is an extremely safe language and is thus primarily used today in avionics, air traffic control, rail systems, embedded systems, medical devices, and communication.

As a general purpose language, you can use it in virtually every interesting area of Computer Science.

Some resources you’ll want to know about are:

The language was designed for complex tasks. Readability was an important design goal, so many people find it verbose. But others consider this is a good thing. Getting work done in Ada is a very pleasant experience because many aspects of good software engineering are enforced by the language.

The language has evolved over time, with the following major versions:

VersionWikibookReference ManualRationale or OverviewStandard
Ada 83 Info RM '83 ISO/IEC 8652:1987
Ada 95 Info ARM 95
AARM 95
Rat 95 ISO/IEC 8652:1995(E) with COR.1:2000
Ada 2005 Info ARM 2005
AARM 2005
Rat 2005 ISO/IEC 8652:1995(E) with COR.1:2001 and AMD.1:2007
Ada 2012 Info ARM 2012
AARM 2012
Rat 2012 ISO/IEC 8652:2012(E)
Ada 2022 Info ARM 2022
AARM 2022
Overview ISO/IEC 8652:2023

The notes on this page are designed to only get you started and cover only the most basic elements of the language. I have notes on Ada concurrency elsewhere, but even these cover only a small subset of the language.

For a more modern and much better tutorial, see the Wikibook or learn.adacore.com.

Hello, World

The simplest kind of program is a simple procedure with no parameters:

hello.adb
with Ada.Text_IO;

procedure Hello is
begin
   Ada.Text_IO.Put_Line ("Hello, world");
end Hello;

The modern way to execute Ada programs is to use the package manager Alire. If you are familiar with Rust, Alire is equivalent to Cargo. If you set Alire up correctly, and ask it to build a binary crate for your hello program, you should be able to run it with:

$ alr run
 Building ada=0.0.1/ada.gpr...
Compile
   [Ada]          hello.adb
Bind
   [gprbind]      hello.bexch
   [Ada]          hello.ali
Link
   [link]         hello.adb
 Build finished successfully in 0.13 seconds.
Hello, world

Since the run command produces a lot of output, you can just do alr build, which puts the executable in the bin folder. Then just run:

$ bin/hello
Hello, world

More Simple Programs

Here’s a program that prints some lucky numbers:

triple.adb
-------------------------------------------------------------------------------
--  This program writes out a table of all Pythagorean triples whose elements
--  are in the range 1..100. Each of the triples are written on a single line
--  of text with each value right-justified in a text field six characters
--  wide.
-------------------------------------------------------------------------------

with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;

procedure Triple is
begin
   Put_Line ("     A     B     C");
   Put_Line ("------------------");
   for C in 1 .. 100 loop
      for B in 1 .. C loop
         for A in 1 .. B loop
            if A ** 2 + B ** 2 = C ** 2 then
               Put (A, Width => 6);
               Put (B, Width => 6);
               Put (C, Width => 6);
               New_Line;
            end if;
         end loop;
      end loop;
   end loop;
end Triple;

And more numbers you know:

fib.adb
-------------------------------------------------------------------------------
--  This program prints out Fibonacci numbers in octal, decimal and hexadecimal
--  in reverse order. The number of Fibonacci numbers that the user wants
--  to see is input on the command line, but if no arguments are given on the
--  command line then the program will prompt the user to input that value.
--
--  This script is meant only to demonstrate a few Ada features, such as user-
--  defined exceptions, enumeration types, the 'Pos attribute, attributes, the
--  reverse keyword, the case statement, and assignment to array slices.
-------------------------------------------------------------------------------

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Command_Line;
use Ada.Text_IO, Ada.Integer_Text_IO, Ada.Command_Line;

procedure Fib is

   Number_Of_Values_Requested : Integer;

   --  In Ada there are a number of predefined exceptions, but we can declare
   --  our own. Too_Few will be raised if the user does not ask for at least
   --  two Fibonacci numbers, and Bad_Argument will be raised if the program
   --  can not make sense out of the command line argument:

   Too_Few, Bad_Argument : exception;

   type Number_List is array (Integer range <>) of Integer;
   type Number_System is (Octal, Decimal, Hex);

   --  The function Get_User_Input returns the user's "input" as follows:
   --  First it checks to see if any argument was entered on the command
   --  line and if so attempts to convert that value to a natural number.
   --  If the command line has no parameters the user is prompted for an
   --  input. In either case, the value input must be greater than or
   --  equal to 2; the function raises Too_Few if it is not.

   function Get_User_Input return Integer is
      Size : Integer;
   begin
      if Argument_Count > 0 then
         Size := Natural'Value (Argument (1));
      else
         Put ("How many numbers do you want (minimum = 2)? ");
         Get (Size);
      end if;
      if Size < 2 then
         raise Too_Few;
      end if;
      return Size;
   exception
      --  Natural'Value raises a Constraint_Error if the string cannot be
      --  converted to a natural. Let's repackage this to a nicer exception
      when Constraint_Error => raise Bad_Argument;
   end Get_User_Input;

   --  Compute (Size) finds and displays the first Size Fibonacci numbers.
   --  It first allocates an array of just the right size to store the
   --  numbers, then loads the array by performing the straightforward
   --  calculations. Then the array is printed backwards three times
   --  with different bases, using the helper function Display.

   procedure Compute (Size : Integer) is
      Fibs : Number_List (1 .. Size);

      procedure Display (B : Number_System) is
      begin
         Put ("Fibonaccis in " & Number_System'Image (B) & " backwards: ");
         New_Line (2);
         for I in reverse Fibs'Range loop
            case B is
               --  The order of arguments should be value, width, base. But
               --  you can use argument association to change things up a bit.
               when Decimal => Put (Fibs (I), 15, 10);
               when Octal => Put (Fibs (I), Base => 8, Width => 15);
               when Hex => Put (Base => 16, Item => Fibs (I), Width => 15);
            end case;
            New_Line;
         end loop;
         New_Line (2);
      end Display;

   begin
      Fibs (1 .. 2) := [1, 1];
      for I in 3 .. Size loop
         Fibs (I) := Fibs (I - 1) + Fibs (I - 2);
      end loop;
      Display (Octal);
      Display (Decimal);
      Display (Hex);
   end Compute;

begin
   Number_Of_Values_Requested := Get_User_Input;
   Compute (Size => Number_Of_Values_Requested);
   Put_Line ("Program successfully completed");
exception
   when Too_Few => Put_Line ("Not enough values requested");
   when Bad_Argument => Put_Line ("Illegal command line argument");
   when Constraint_Error => Put_Line ("I can't find that many");
   when Data_Error => Put_Line ("That's not a decent response");
end Fib;

And prime numbers, because you may have expected to see them:

prime_sieve.adb
------------------------------------------------------------------------------
--  This program computes and prints all the prime numbers up to and including
--  a number which is provided as the sole argument on the command line, or,
--  if no command  line arguments are given, input by the user in response to
--  a prompt, and then reports how many primes it found.
------------------------------------------------------------------------------

with Ada.Text_IO, Ada.Integer_Text_IO, Ada.Command_Line;
use Ada.Text_IO, Ada.Integer_Text_IO, Ada;

procedure Prime_Sieve is

   Limit    : Natural;                    -- will find primes up to this
   How_Many : Natural;                    -- how many primes were found

   procedure Compute_Primes (Up_To : Natural; Count : out Natural) is
      Sieve : array (2 .. Up_To) of Boolean := (others => True);
   begin
      Count := 0;
      for I in Sieve'Range loop
         if Sieve (I) then
            Put (Item => I, Width => 12, Base => 10);
            Count := Count + 1;
            declare                       -- start a block
               K : Natural := I;          -- variable local to the block
            begin
               while K <= Sieve'Last - I loop
                  K := K + I;             -- go to next multiple
                  Sieve (K) := False;     -- check off this multiple
               end loop;
            end;                          -- after the block K does not exist
            if Count mod 6 = 0 then       -- write six primes per row
               New_Line;
            end if;
         end if;
      end loop;
      New_Line (2);
   end Compute_Primes;

begin
   if Command_Line.Argument_Count = 0 then
      Put ("Find primes up to what number? ");
      Get (Limit);
   else
      Limit := Natural'Value (Command_Line.Argument (1));
   end if;
   Compute_Primes (Up_To => Limit, Count => How_Many);
   Put_Line ("I found" & Natural'Image (How_Many) & " primes.");
exception
   when Constraint_Error => Put_Line ("Illegal command line argument");
   when Data_Error => Put_Line ("I don't understand that input");
end Prime_Sieve;

Language Structure

The Ada language is comprised of two parts:

Core Language

Required of all implementations.

ARM Clauses 1-13, and Annexes A, B, and J.

Specialized Needs Annexes

Not required of an implementation.

ARM Annexes C, D, E, F, G, and H.

You should browse the reference manual table of contents now to see what these clauses and annexes refer to.

Reserved Words

Ada is clearly not a small language.

abort
abs
abstract
accept
access
aliased
all
and
array
at
begin
body
case
constant
declare
delay
delta
digits
do
else
elsif
end
entry
exception
exit
for
function
generic
goto
if
in
interface
is
limited
loop
mod
new
not
null
of
or
others
out
overriding
package
parallel
pragma
private
procedure
protected
raise
range
record
rem
renames
requeue
return
reverse
select
separate
some
subtype
synchronized
tagged
task
terminate
then
type
until
use
when
while
with
xor

Program Structure

An Ada program is made up of a collection of program units, which can be either subprograms or packages. Ada units are designed to have well specified interfaces so they are highly reusable.

Here is a trivial example of a program made up of a package exporting a type Float_Array and two functions, Mean and Variance:

stats.ads
package Stats is

   type Float_Array is array (Integer range <>) of Float;

   function Mean (A : Float_Array) return Float;
   function Variance (A : Float_Array) return Float;

end Stats;

To show off information hiding features, the package contains a local, non-exported utility function called Sum:

stats.adb
package body Stats is

   function Sum (A : Float_Array) return Float is (A'Reduce("+", 0.0));

   function Mean (A : Float_Array) return Float is
      (Sum (A) / Float (A'Length));

   function Variance (A : Float_Array) return Float is
      M            : constant Float := Mean (A);
      Square_Diffs : Float_Array (A'Range);
   begin
      Square_Diffs := [for I in A'Range => (A (I) - M) ** 2];
      return Mean (Square_Diffs);
   end Variance;

end Stats;

Here’s a command line application that shows off the functions:

show_stats.adb
with Ada.Text_IO, Ada.Float_Text_IO, Stats;
use Ada.Text_IO, Ada.Float_Text_IO, Stats;

procedure Show_Stats is
   A : constant Float_Array := [3.0, 5.0, 8.0, 2.0];
begin
   Put (Mean (A)); New_Line;
   Put (Variance (A)); New_Line;
end Show_Stats;

There was a lot going on there!

Exercise: Add functions for median and mode.

Types

See Section 3 of the Reference Manual, particularly the note at the bottom of Section 3.2 which gives a really nice hierarchy of the kinds of types in the type system, and a few of the built-in (standard) types. Here’s a summary of that information:

                     All Types
                         │
       ┌─────────────────┴─────────────────┐
       │                                   │
   Elementary                            Composite
       │                                   │
   ┌───┴──────┐                      ┌─────┴─────────┐
   │          │                      │               │
Scalar      Access               Untagged          Tagged
│           ├─ To Object         ├─ Array          ├─ Nonlimited Tagged Record
│           └─ To Subprogram     │  └─ String      └─ Limited Tagged
│                                ├─ Record            ├─ Limited Tagged Record
├─ Discrete                      ├─ Task              └─ Synchronized Tagged
│  ├─ Enumeration                └─ Protected            ├─ Tagged Task
│  │  ├─ Character                                       └─ Tagged Protected
│  │  └─ Boolean
│  └─ Integer
│     ├─ Signed
│     └─ Modular
│
└─ Real
   ├─ Floating Point
   └─ Fixed Point
      ├─ Ordinary
      └─ Decimal

Here’s a program that illustrates a few of the simplest types in use:

TODO

Expressions

TODO

Statements

We’ve seen a lot of the statements above, so for completeness, here’s a list of every kind of Ada statement:

null
assignment
goto
code
if
case
for
while
parallel
block
exit
procedure call
return
entry call
conditional entry call
timed entry call
requeue
delay
delay until
abort
raise
accept
select
selective accept
asynchronous select

Generics

Here’s another classic pedagogical exercise: creating an abstract data types for stacks, from first principles, using linked lists. The stack element type will be generic. First, the package specification:

unbounded_stacks.ads
generic
   type Element is private;
package Unbounded_Stacks is

   type Stack is limited private;

   Overflow, Underflow, No_Top : exception;

   function Is_Empty (S : Stack) return Boolean;
   function Size (S : Stack) return Natural;
   procedure Push (S : in out Stack; E : Element);
   function Top (S : Stack) return Element;
   procedure Pop (S : in out Stack);
   procedure Pop (S : in out Stack; E : out Element);

private

   type Node;
   type Stack is access Node;
   type Node is record
      Data : Element;
      Link : Stack;
   end record;

end Unbounded_Stacks;

Next, the package body, in a separate file:

unbounded_stacks.adb
package body Unbounded_Stacks is

   function Is_Empty (S : Stack) return Boolean is (S = null);

   function Size (S : Stack) return Natural is
      (if S = null then 0 else 1 + Size (S.Link));

   procedure Push (S : in out Stack; E : Element) is
   begin
      S := new Node'(E, S);
   exception
      when Storage_Error => raise Overflow;
   end Push;

   function Top (S : Stack) return Element is
   begin
      if Is_Empty (S) then
         raise No_Top;
      end if;
      return S.Data;
   end Top;

   procedure Pop (S : in out Stack) is
   begin
      if Is_Empty (S) then
         raise Underflow;
      end if;
      S := S.Link;
   end Pop;

   procedure Pop (S : in out Stack; E : out Element) is
   begin
      if Is_Empty (S) then
         raise Underflow;
      end if;
      E := S.Data;
      S := S.Link;
   end Pop;

end Unbounded_Stacks;

Now, if we want to add new functionality to our ADT, we can use a child package. This is a pretty decent illustration of when to use child packages, since it’s probably best not to pollute the basic stack package with I/O, which not everyone may want:

unbounded_stacks-io.ads
------------------------------------------------------------------------------
--  unbounded_stacks-io.ads
--
--  A generic child package which enables output for unbounded stacks.
--
--  Generic Parameters:
--
--    Put (F, E)     procedure to display element E to file F.
--
--  Operations:
--
--    Put (F, S)     write S to file F in the form  <x1 x2 ... xn>  from top
--                   to bottom.
--    Put (S)        Same as Put (Current_Output, S)
------------------------------------------------------------------------------

with Ada.Text_IO;
use Ada.Text_IO;

generic
   with procedure Put (F : File_Type; E : Element);
package Unbounded_Stacks.IO is

   procedure Put (F : File_Type; S : Stack);
   procedure Put (S : Stack);

end Unbounded_Stacks.IO;

Here’s the body of the child package:

unbounded_stacks-io.adb
package body Unbounded_Stacks.IO is

   procedure Put (F : File_Type; S : Stack) is
      T : Stack := S;
   begin
      Put (F, "< ");
      while T /= null loop
         Put (F, T.Data);
         Put (' ');
         T := T.Link;
      end loop;
      Put (F, '>');
   end Put;

   procedure Put (S : Stack) is
   begin
      Put (Current_Output, S);
   end Put;

end Unbounded_Stacks.IO;

To exercise the stack package, we write a little driver:

test_unbounded_stacks.adb
with Ada.Text_IO, Unbounded_Stacks, Unbounded_Stacks.IO;
use Ada.Text_IO;

procedure Test_Unbounded_Stacks is

   package My_Stacks is new Unbounded_Stacks (Character);
   use My_Stacks;

   package My_Stacks_IO is new My_Stacks.IO (Put);
   use My_Stacks_IO;

   S : Stack;

   procedure Test is
      Option : Character;
      Data : Character;
   begin
      loop
         Put (S);
         Put_Line (" Length =" & Integer'Image (Size (S)));
         Put ("Empty pusH Pop Quit: ");
         Get (Option);
         New_Line;
         case Option is
            when 'h' =>
               begin
                  Put ("push what? "); Get (Data); Push (S, Data);
               exception
                  when Overflow => Put_Line ("Cannot push onto full stack");
               end;
            when 'p' =>
               begin
                  Pop (S, Data); Put (Data); Put_Line (" popped");
               exception
                  when Underflow => Put_Line ("Cannot pop from empty stack");
               end;
            when 'e' =>
               Put (if Is_Empty (S) then "Empty" else "Not Empty");
            when 'q' => exit;
            when others => null;
         end case;
         New_Line;
      end loop;
   end Test;

begin
   Test;
end Test_Unbounded_Stacks;

Object Oriented Features

TODO

Contracts

TODO

Containers

TODO

Concurrency

Concurrency features have been built into Ada since its inception, and is one of the language's key strengths. The topic is so large that full-length books have been written about Ada concurrency.

My notes are on a separate page.

Testing

TODO

Standard Library

Ada features a really cool and comprehensive standard library. The full list of units is summarized at the beginning of Annex A of the Reference Manual. The library is organized into a hierarchy, which can be used to organize code and provide a namespace for identifiers.

There are three root library units: Ada, System, and Interfaces. Here’s a listing for scanning. See the Reference Manual index to dig deeper.

Ada — A.2
    Assertions — 11.4.2
    Asynchronous_Task_Control — D.11
    Calendar — 9.6
        Arithmetic — 9.6.1
        Formatting — 9.6.1
        Time_Zones — 9.6.1
    Characters — A.3.1
        Conversions — A.3.4
        Handling — A.3.2
        Latin_1 — A.3.3
    Command_Line — A.15
    Complex_Text_IO — G.1.3
    Containers — A.18.1
        Bounded_Doubly_Linked_Lists — A.18.20
        Bounded_Hashed_Maps — A.18.21
        Bounded_Hashed_Sets — A.18.23
        Bounded_Indefinite_Holders — A.18.32
        Bounded_Multiway_Trees — A.18.25
        Bounded_Ordered_Maps — A.18.22
        Bounded_Ordered_Sets — A.18.24
        Bounded_Priority_Queues — A.18.31
        Bounded_Synchronized_Queues — A.18.29
        Bounded_Vectors — A.18.19
        Doubly_Linked_Lists — A.18.3
        Generic_Array_Sort — A.18.26
        Generic_Constrained_Array_Sort — A.18.26
        Generic_Sort — A.18.26
        Hashed_Maps — A.18.5
        Hashed_Sets — A.18.8
        Indefinite_Doubly_Linked_Lists — A.18.12
        Indefinite_Hashed_Maps — A.18.13
        Indefinite_Hashed_Sets — A.18.15
        Indefinite_Holders — A.18.18
        Indefinite_Multiway_Trees — A.18.17
        Indefinite_Ordered_Maps — A.18.14
        Indefinite_Ordered_Sets — A.18.16
        Indefinite_Vectors — A.18.11
        Multiway_Trees — A.18.10
        Ordered_Maps — A.18.6
        Ordered_Sets — A.18.9
        Synchronized_Queue_Interfaces — A.18.27
        Unbounded_Priority_Queues — A.18.30
        Unbounded_Synchronized_Queues — A.18.28
        Vectors — A.18.2
    Decimal — F.2
    Direct_IO — A.8.4
    Directories — A.16
        Hierarchical_File_Names — A.16.1
        Information — A.16
    Dispatching — D.2.1
        EDF — D.2.6
        Non_Preemptive — D.2.4
        Round_Robin — D.2.5
    Dynamic_Priorities — D.5.1
    Environment_Variables — A.17
    Exceptions — 11.4.1
    Execution_Time — D.14
        Group_Budgets — D.14.2
        Interrupts — D.14.3
        Timers — D.14.1
    Finalization — 7.6
    Float_Text_IO — A.10.9
    Float_Wide_Text_IO — A.11
    Float_Wide_Wide_Text_IO — A.11
    Integer_Text_IO — A.10.8
    Integer_Wide_Text_IO — A.11
    Integer_Wide_Wide_Text_IO — A.11
    Interrupts — C.3.2
        Names — C.3.2
    IO_Exceptions — A.13
    Iterator_Interfaces — 5.5.1
    Locales — A.19
    Numerics — A.5
        Big_Numbers — A.5.5
            Big_Integers — A.5.6
            Big_Reals — A.5.7
        Complex_Arrays — G.3.2
        Complex_Elementary_Functions — G.1.2
        Complex_Types — G.1.1
        Discrete_Random — A.5.2
        Elementary_Functions — A.5.1
        Float_Random — A.5.2
        Generic_Complex_Arrays — G.3.2
        Generic_Complex_Elementary_Functions — G.1.2
        Generic_Complex_Types — G.1.1
        Generic_Elementary_Functions — A.5.1
        Generic_Real_Arrays — G.3.1
        Real_Arrays — G.3.1
    Real_Time — D.8
        Timing_Events — D.15
    Sequential_IO — A.8.1
    Storage_IO — A.9
    Streams — 13.13.1
        Storage_Streams — 13.13.1
            Bounded_FIFO_Streams — 13.13.1
            FIFO_Streams — 13.13.1
      Stream_IO — A.12.1
    Strings — A.4.1
        Bounded — A.4.4
            Equal_Case_Insensitive — A.4.10
            Hash — A.4.9
            Hash_Case_Insensitive — A.4.9
            Less_Case_Insensitive — A.4.10
        Equal_Case_Insensitive — A.4.10
        Fixed — A.4.3
            Equal_Case_Insensitive — A.4.10
            Hash — A.4.9
            Hash_Case_Insensitive — A.4.9
            Less_Case_Insensitive — A.4.10
        Hash — A.4.9
        Hash_Case_Insensitive — A.4.9
        Less_Case_Insensitive — A.4.10
        Maps — A.4.2
            Constants — A.4.6
        Text_Buffers — A.4.12
            Bounded — A.4.12
            Unbounded — A.4.12
        Unbounded — A.4.5
            Equal_Case_Insensitive — A.4.10
            Hash — A.4.9
            Hash_Case_Insensitive — A.4.9
            Less_Case_Insensitive — A.4.10
        UTF_Encoding — A.4.11
            Conversions — A.4.11
            Strings — A.4.11
            Wide_Strings — A.4.11
            Wide_Wide_Strings — A.4.11
        Wide_Bounded — A.4.7
            Wide_Equal_Case_Insensitive — A.4.7
            Wide_Hash — A.4.7
            Wide_Hash_Case_Insensitive — A.4.7
        Wide_Equal_Case_Insensitive — A.4.7
        Wide_Fixed — A.4.7
            Wide_Equal_Case_Insensitive — A.4.7
            Wide_Hash — A.4.7
            Wide_Hash_Case_Insensitive — A.4.7
        Wide_Hash — A.4.7
        Wide_Hash_Case_Insensitive — A.4.7
        Wide_Maps — A.4.7
            Wide_Constants — A.4.7
        Wide_Unbounded — A.4.7
            Wide_Equal_Case_Insensitive — A.4.7
            Wide_Hash — A.4.7
            Wide_Hash_Case_Insensitive — A.4.7
        Wide_Wide_Bounded — A.4.8
            Wide_Wide_Equal_Case_Insensitive — A.4.8
            Wide_Wide_Hash — A.4.8
            Wide_Wide_Hash_Case_Insensitive — A.4.8
        Wide_Wide_Equal_Case_Insensitive — A.4.8
        Wide_Wide_Fixed — A.4.8
            Wide_Wide_Equal_Case_Insensitive — A.4.8
            Wide_Wide_Hash — A.4.8
            Wide_Wide_Hash_Case_Insensitive — A.4.8
        Wide_Wide_Hash — A.4.8
        Wide_Wide_Hash_Case_Insensitive — A.4.8
        Wide_Wide_Maps — A.4.8
            Wide_Wide_Constants — A.4.8
        Wide_Wide_Unbounded — A.4.8
            Wide_Wide_Equal_Case_Insensitive — A.4.8
            Wide_Wide_Hash — A.4.8
            Wide_Wide_Hash_Case_Insensitive — A.4.8
    Synchronous_Barriers — D.10.1
    Synchronous_Task_Control — D.10
        EDF — D.10
    Tags — 3.9
        Generic_Dispatching_Constructor — 3.9
    Task_Attributes — C.7.2
    Task_Identification — C.7.1
    Task_Termination — C.7.3
    Text_IO — A.10.1
        Bounded_IO — A.10.11
        Complex_IO — G.1.3
        Editing — F.3.3
        Text_Streams — A.12.2
        Unbounded_IO — A.10.12
    Unchecked_Conversion — 13.9
    Unchecked_Deallocate_Subpool — 13.11.5
    Unchecked_Deallocation — 13.11.2
    Wide_Characters — A.3.1
        Handling — A.3.5
    Wide_Command_Line — A.15.1
    Wide_Directories — A.16.2
    Wide_Environment_Variables — A.17.1
    Wide_Text_IO — A.11
        Complex_IO — G.1.4
        Editing — F.3.4
        Text_Streams — A.12.3
        Wide_Bounded_IO — A.11
        Wide_Unbounded_IO — A.11
        Wide_Wide_Characters — A.3.1
        Handling — A.3.6
    Wide_Wide_Command_Line — A.15.1
    Wide_Wide_Directories — A.16.2
    Wide_Wide_Environment_Variables — A.17.1
    Wide_Wide_Text_IO — A.11
        Complex_IO — G.1.5
        Editing — F.3.5
        Text_Streams — A.12.4
        Wide_Wide_Bounded_IO — A.11
        Wide_Wide_Unbounded_IO — A.11
  Interfaces — B.2
      C — B.3
          Pointers — B.3.2
          Strings — B.3.1
      COBOL — B.4
      Fortran — B.5
  System — 13.7
      Address_To_Access_Conversions — 13.7.2
      Atomic_Operations — C.6.1
        Exchange — C.6.2
        Integer_Arithmetic — C.6.4
        Modular_Arithmetic — C.6.5
        Test_And_Set — C.6.3
    Machine_Code — 13.8
    Multiprocessors — D.16
        Dispatching_Domains — D.16.1
    RPC — E.5
    Storage_Elements — 13.7.1
    Storage_Pools — 13.11
        Subpools — 13.11.4

What’s Next?

Please, read the Wikibook. There wasn’t much covered here.