Ada: Subprograms

Ada has two kinds of subprograms: procedures (statements that act) and functions (computations that return exactly one value). The split is deliberate — functions are guaranteed side-effect-light, which makes call sites truthful and later enables contracts and proofs.

Procedures and Functions

with Ada.Text_IO; use Ada.Text_IO;

procedure Subprogram_Demo is

   --  A procedure: performs an action, returns nothing
   procedure Greet (Name : in String) is
   begin
      Put_Line ("Hello, " & Name & "!");
   end Greet;

   --  A function: computes and returns exactly one value
   function Square (X : in Integer) return Integer is
   begin
      return X * X;
   end Square;

   N : constant Integer := 7;
begin
   Greet ("Ada");                        -- a statement
   Put_Line (Integer'Image (Square (N)));   -- an expression: 49
end Subprogram_Demo;

Functions cannot be called as statements, and procedures cannot appear in expressions — the compiler enforces the distinction that C's int f() blurs.

Parameter Modes

Every parameter declares a mode: which direction data flows. This is Ada's replacement for guessing what a const T* or T* means:

ModeMeaningBody may…
in (default)read-only inputread, never assign
outresult outputassign, initial value uninteresting
in outupdate in placeread and assign
procedure Modes_Demo is
   procedure Swap (A, B : in out Integer) is
      Tmp : constant Integer := A;
   begin
      A := B;         -- legal: mode is in out
      B := Tmp;
   end Swap;

   procedure Normalize (X : in out Float; Scale : in Float) is
   begin
      --  Scale := 1.0;   -- compile error: Scale is read-only (in)
      X := X / Scale;
   end Normalize;
begin
   null;
end Modes_Demo;

The compiler checks every mode promise: assigning to an in parameter or reading an out parameter before assigning it are errors. This makes subprogram signatures self-documenting in a way headers in other languages never are.

Overloading

Subprograms may share a name when their parameter profiles differ. The compiler picks by argument types — and ambiguity is an error, not a guess:

procedure Overload_Demo is
   function Max (A, B : Integer) return Integer is
     (if A > B then A else B);          -- expression function: compact body

   function Max (A, B : Float) return Float is
     (if A > B then A else B);
begin
   null;   -- Max (3, 5) picks the Integer one; Max (2.0, 9.5) the Float one
end Overload_Demo;

The example also shows an expression function: for a body that is a single expression, is (expression) replaces begin ... return ... end.

Recursion and Declarations

Subprograms can be recursive, and a body can appear before its callers' declarations via is separate or forward declarations in packages — covered in the Packages lesson. A recursive function needs no special keyword:

procedure Recursion_Demo is
   function Factorial (N : Natural) return Natural is
     (if N <= 1 then 1 else N * Factorial (N - 1));
begin
   null;   -- Factorial (5) = 120; the type bounds recursion, no tail-call tricks
end Recursion_Demo;

Next: Input/Output.