Parameter Modes: in, out, in out & Passing Semantics
Use the three parameter modes to state data flow explicitly, understand that 'in' parameters are constants, how 'out' and 'in out' return results, when parameters are passed by copy or by reference, and aliasing rules.
Instead of pointers and conventions, Ada lets you declare the direction of every parameter: in (read-only input), out (result produced by the subprogram), or in out (read and updated). The compiler enforces these modes, readers see the data flow from the specification alone, and the compiler is free to choose the most efficient passing mechanism.
The Three Modes
in (the default when no mode is written): the parameter acts as a constant inside the subprogram — assigning to it is a compile error. out: the subprogram is expected to assign a value; its initial value on entry is generally not meaningful (except for access types, records with default components, and some other cases). in out: the actual parameter's value is read on entry and the (possibly updated) value flows back to the caller. Actual parameters for out and in out must be variables (not constants or expressions).
• in (default): read-only constant. • out: produced by the subprogram; don't read before writing. • in out: read and updated. • Actuals for out / in out must be variables.
By Copy or by Reference?
Elementary types (scalars, access types) are always passed by copy: in copies in, out copies out, in out copies both ways. Tagged types, limited types, task and protected types are always passed by reference. For other composite types (plain arrays and records) the compiler chooses — usually by reference for large objects. Because of this, correct Ada programs must not depend on the mechanism, which is why the language restricts aliasing: passing the same variable as two out/in out parameters of elementary type is illegal when it would make the result depend on the mechanism.
• Scalars/access: by copy. Tagged/limited/task/protected: by reference. • Other arrays/records: compiler's choice. • Never rely on the mechanism; avoid aliasing parameters.
Code Examples
Divide returns two results through out parameters, Increment updates an in out counter with a default step, and Swap exchanges two variables. Output: 17 / 5 -> 3 remainder 2 Count = 16 After swap: X = 2, Y = 1
Assigning to an 'in' parameter. The real GNAT diagnostic is: l15_err.adb:4:07: error: assignment to "in" mode parameter not allowed procedure Reset (Value: Integer) is begin Value:= 0; end Reset;
procedure Reset (Value : out Integer) is begin Value := 0; end Reset;
Without a mode the parameter is 'in' (constant); use out or in out to modify the caller's variable.
Increment (5); -- Counter: in out Integer N: Integer:= 5;... Increment (N);
An in out actual must be a variable, not a literal or expression.
procedure Get (Result : out Integer) is begin Result := Result + 1; -- reads undefined value end Get;
procedure Get (Result : in out Integer) is ...
An out parameter's initial value is not meaningful for scalars; use in out when you need to read it.
What is the mode of a parameter declared without a mode? A. out B. in out C. in D. access
Which mode should a parameter have if the subprogram both reads and modifies it? A. in B. out C. in out D. access
How are tagged-type parameters passed? A. By copy B. By reference C. Compiler's choice D. By name B. By reference, always.
Can you pass the literal 5 as an 'out' parameter? A. Yes B. No, it must be a variable C. Only in Ada 2022 D. Only for functions
B. No — out and in out actuals must be variables.
Why does this fail to compile?
Real GNAT output: l15_err.adb:4:07: error: assignment to "in" mode parameter not allowed Make the parameter 'out' (or 'in out') if the procedure is meant to set the caller's variable.
Write a procedure Min_Max (A, B : Integer; Lo, Hi : out Integer).
procedure Min_Max (A, B : Integer; Lo, Hi : out Integer) is begin Lo := Integer'Min (A, B); Hi := Integer'Max (A, B); end Min_Max;
Two results are returned through out parameters; 'Min and 'Max avoid an if statement.
with Ada.Text_IO; use Ada.Text_IO;
procedure L15_Modes is
-- in: read-only input (the default mode)
-- out: result written by the subprogram
-- in out: value read and updated
procedure Divide (Dividend, Divisor : in Integer;
Quotient, Remainder : out Integer) is
begin
Quotient := Dividend / Divisor;
Remainder := Dividend rem Divisor;
end Divide;
procedure Increment (Counter : in out Integer; By : Integer := 1) is
begin
Counter := Counter + By;
end Increment;
procedure Swap (A, B : in out Integer) is
Temp : constant Integer := A;
begin
A := B;
B := Temp;
end Swap;
Q, R : Integer;
Count : Integer := 10;
X : Integer := 1;
Y : Integer := 2;
begin
Divide (17, 5, Q, R);
Put_Line ("17 / 5 ->" & Integer'Image (Q) & " remainder" & Integer'Image (R));
Increment (Count);
Increment (Count, By => 5);
Put_Line ("Count =" & Integer'Image (Count));
Swap (X, Y);
Put_Line ("After swap: X =" & Integer'Image (X) & ", Y =" & Integer'Image (Y));
end L15_Modes;procedure L15_Err is
procedure Reset (Value : in Integer) is
begin
Value := 0; -- an "in" parameter is a constant inside the subprogram
end Reset;
N : constant Integer := 5;
begin
Reset (N);
end L15_Err;