Arrays: Constrained, Unconstrained, Aggregates & Slices
Declare constrained and unconstrained array types, index arrays by any discrete type (including enumerations), write positional, named, others and iterated aggregates, use array attributes ('First, 'Last, 'Range, 'Length), slices, sliding, whole-array assignment, equality and concatenation.
Arrays in Ada are first-class values: they know their own bounds, can be indexed by any discrete type, can be assigned and compared as a whole, and are always index-checked. Unconstrained array types let one subprogram work on arrays of any length without passing a separate size parameter — the bounds travel with the array.
Array Types and Indexing
A constrained array type fixes the bounds: 'type Week_Hours is array (1 .. 7) of Natural;'. The index can be any discrete type or range — 'type Color_Count is array (Color) of Natural;' indexes by an enumeration, so Counts (Blue) is legal and Counts (4) is not. Indexing uses parentheses, A (I). Every index is checked: an out-of-range index raises Constraint_Error rather than reading random memory. Bounds need not start at 0 or 1; choose the range that matches the problem (array (1900 .. 2100) of Rainfall).
An unconstrained array type leaves the bounds open: 'type Int_Array is array (Positive range <>) of Integer;' (the box <> means 'to be decided'). Each object must be constrained when created, either explicitly (X : Int_Array (1 .. 6)) or from its initial value (Data : Int_Array := [5, 3, 9]). Subprogram parameters of an unconstrained type accept arrays of any length — this is how String works: type String is array (Positive range <>) of Character.
• Constrained: array (1 .. 7) of T — bounds fixed by the type. • Unconstrained: array (Positive range <>) of T — bounds fixed per object. • Index by any discrete type, including enumerations. • Every index is checked (Constraint_Error).
Attributes and Aggregates
A'First, A'Last, A'Length and A'Range describe an array's bounds. Always loop with 'for I in A'Range' (or 'for X of A') instead of assuming the array starts at 1 — a slice passed to a subprogram keeps its original indices.
Aggregates build array values. In Ada 2022 array aggregates use square brackets: positional [8, 8, 8, 8, 6, 0, 0]; named [Red => 3, Green .. Blue => 0]; with others [Red => 3, others => 0]; iterated [for I in 1 .. 5 => I * I]; empty []. 'others' needs a context that determines the bounds. The older parenthesized form (1, 2, 3) is still accepted, but GNAT warns it is obsolescent in Ada 2022 mode.
• 'First 'Last 'Length 'Range — use them instead of hard-coded bounds. • [1, 2, 3] [1 => 10, others => 0] [for I in R => F (I)] []. • 'others' requires known bounds from the context.
Slices, Assignment, Equality and Concatenation
A slice A (2 .. 4) denotes a contiguous part of a one-dimensional array and can be read, passed or assigned: Data (1 .. 3) := Data (4 .. 6);. Assignment copies all components (arrays are values, not references) and requires matching lengths — the indices may differ, a rule called sliding. = and /= compare arrays component-wise; relational operators work lexicographically on arrays of discrete components; & concatenates arrays and single components.
• A (L .. H) is a slice — assignable and passable, keeps original indices. • := copies the whole array; lengths must match (sliding allowed). • = compares all components; & concatenates.
Code Examples
Show and Sum accept any Int_Array. The slice Data (2.. 4) keeps indices 2.. 4. Changing Copy does not affect Data because assignment copies. The final loop reads Data (6) successfully and then Data (7), which raises Constraint_Error handled by the procedure's exception handler. Output: Hours'Length = 7, Friday = 6 RED= 3 GREEN= 0 BLUE= 2 Data ( 1.. 6): 5 3 9 1 7 2 Slice Data (2.. 4) ( 2.. 4): 3 9 1 Sum (Data) = 27, Sum of slice = 13 Data (1) after changing Copy (1): 5 Copy = Data? FALSE After slice assignment ( 1.. 6): 1 7 2 1 7 2 Zeros ( 1.. 4): 0 0 0 0 Squares ( 1.. 5): 1 4 9 16 25 Concatenation ( 1.. 4): 1 4 0 99 Data ( 6) = 2 Data (7) raised Constraint_Error (index check) for I in 1.. A'Length loop Total:= Total + A (I);
for I in A'Range loop Total := Total + A (I);
A slice such as Data (2 .. 4) starts at 2; 'Range always matches the actual bounds.
X: Int_Array; -- unconstrained type, no bounds X: Int_Array (1.. 10); -- or X: Int_Array:= [1, 2, 3];
Objects of an unconstrained array type must get bounds at declaration.
Data (1 .. 3) := Data (1 .. 4);
Data (1 .. 3) := Data (2 .. 4);
Array assignment requires equal lengths; otherwise Constraint_Error.
What does 'range <>' mean in an array type declaration? A. Empty array B. Bounds are decided per object (unconstrained) C. Dynamic resizing D. Any index type
B. The array type is unconstrained; each object supplies its bounds.
After 'Copy := Data; Copy (1) := 100;', what is Data (1)? A. 100 B. Unchanged — arrays are copied by assignment C. Undefined D. Compile error
B. Unchanged (verified: the example prints 5).
What is the first index of the slice Data (2.. 4) when passed to a subprogram? A. 1 B. 0 C. 2 D. Depends on compiler C. 2 — slices keep their indices.
Which is an Ada 2022 iterated aggregate? A. {I*I for I in 1..5} B. [for I in 1.. 5 => I * I] C. (1.. 5 => I * I) D. map(1..5, square) Trace the array example.
Real output: Hours'Length = 7, Friday = 6 RED= 3 GREEN= 0 BLUE= 2 Data ( 1 .. 6 ): 5 3 9 1 7 2 Slice Data (2 .. 4) ( 2 .. 4 ): 3 9 1 Sum (Data) = 27, Sum of slice = 13 Data (1) after changing Copy (1): 5 Copy = Data? FALSE After slice assignment ( 1 .. 6 ): 1 7 2 1 7 2 Zeros ( 1 .. 4 ): 0 0 0 0 Squares ( 1 .. 5 ): 1 4 9 16 25 Concatenation ( 1 .. 4 ): 1 4 0 99 Data ( 6 ) = 2 Data (7) raised Constraint_Error (index check)
Write a function Reverse_Of (A : Int_Array) return Int_Array that works for arrays with any bounds.
function Reverse_Of (A : Int_Array) return Int_Array is Result : Int_Array (A'Range); begin for I in A'Range loop Result (A'First + A'Last - I) := A (I); end loop; return Result; end Reverse_Of;
Result gets the same bounds as A, and A'First + A'Last - I mirrors any index range, so it also works for slices.
with Ada.Text_IO; use Ada.Text_IO;
procedure L19_Arrays is
-- Constrained array type: bounds are part of the type.
type Week_Hours is array (1 .. 7) of Natural;
-- Array indexed by an enumeration type.
type Color is (Red, Green, Blue);
type Color_Count is array (Color) of Natural;
-- Unconstrained array type: each object chooses its own bounds.
type Int_Array is array (Positive range <>) of Integer;
procedure Show (Label : String; A : Int_Array) is
begin
Put (Label & " (" & Integer'Image (A'First) & " .." & Integer'Image (A'Last) & " ):");
for V of A loop
Put (Integer'Image (V));
end loop;
New_Line;
end Show;
function Sum (A : Int_Array) return Integer is
Total : Integer := 0;
begin
for I in A'Range loop
Total := Total + A (I);
end loop;
return Total;
end Sum;
Hours : constant Week_Hours := [8, 8, 8, 8, 6, 0, 0]; -- positional aggregate
Counts : Color_Count := [Red => 3, others => 0]; -- named aggregate with others
Data : Int_Array := [5, 3, 9, 1, 7, 2]; -- bounds 1 .. 6 from the aggregate
Copy : Int_Array (1 .. 6);
Zeros
…