Ada: Loops
Ada has three loop forms — for, while, and plain loop — plus exit and next to leave or skip iterations. All are closed with end loop;, and none of them can run off the end of an array unnoticed.
The for Loop
The for loop iterates a discrete range. The loop variable is implicitly declared by the loop, has the range's type, and does not exist after the loop — there is no way to leak it or overwrite it mid-iteration:
with Ada.Text_IO; use Ada.Text_IO;
procedure For_Demo is
begin
for I in 1 .. 5 loop -- I is constant inside the loop
Put_Line (Integer'Image (I));
end loop;
for I in reverse 1 .. 5 loop -- counts DOWN: 5, 4, 3, 2, 1
Put_Line (Integer'Image (I));
end loop;
for I in 2 .. 10 loop
exit when I * I > 30; -- leave early: I*I exceeds 30 at I = 6
Put_Line (Integer'Image (I * I));
end loop;
end For_Demo;
Assigning to I is a compile error — the loop variable is a constant. This kills the classic off-by-one and i = i + 1 bugs in one rule.
Iterating Arrays Safely
The range can come from any discrete expression — most often an array attribute, which makes the loop bounds impossible to get wrong:
procedure Sum_Demo is
type Int_Array is array (Positive range <>) of Integer; -- unconstrained
Data : constant Int_Array := (10, 20, 30, 40);
Sum : Integer := 0;
begin
for I in Data'Range loop -- exactly the valid indices, whatever they are
Sum := Sum + Data (I);
end loop;
-- Sum = 100. "for I in 1 .. Data'Last" would break if the index started at 0;
-- 'Range uses the actual bounds of THIS array.
end Sum_Demo;
while and Plain loop
while re-tests its condition before every iteration. The plain loop repeats until an exit runs — the idiom for unbounded iteration (event loops, retry logic, input parsing):
with Ada.Text_IO; use Ada.Text_IO;
procedure While_Demo is
Balance : Integer := 100;
begin
while Balance > 0 loop -- condition tested before each pass
Balance := Balance - 30;
end loop;
-- Balance is now -20: the last subtraction overshot — a while cannot
-- stop mid-pass. When that matters, use loop + exit:
Balance := 100;
loop
Balance := Balance - 30;
exit when Balance <= 0; -- checked AFTER the work, so no overshoot
end loop;
Put_Line (Integer'Image (Balance)); -- -20 both times; the placement differs
end While_Demo;
The distinction matters in real systems: while tests before the body, exit when tests after. Ada's loop ... exit when ... end loop; replaces C's for (;;) + break with a visible stopping condition.
next and Loop Labels
next skips to the next iteration; exit leaves the loop. In nested loops, label them so the target is explicit — no goto needed:
procedure Grid_Demo is
begin
Outer :
for Row in 1 .. 3 loop
for Col in 1 .. 3 loop
if Row = Col then
next Outer; -- skip this ENTIRE row, not just the cell
end if;
null; -- process the (Row, Col) cell here
end loop;
end loop Outer;
end Grid_Demo;
exit Outer; would leave both loops at once. The label makes multi-level control flow readable and provable. Next: Strings.