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.