Ada Reference Manual (Ada 2022) — Legal Information

# 5.5 Loop Statements

1/5
A loop_statement includes a sequence_of_statements that is to be executed repeatedly, zero or more times with the iterations running sequentially or concurrently with one another.

#### Syntax

2
loop_statement ::=
[loop_statement_identifier:]
[iteration_scheme] loop
sequence_of_statements
end loop [loop_identifier];
3/5
iteration_scheme ::= while condition
| for loop_parameter_specification
| for iterator_specification
| [parallel [aspect_specification]]
for procedural_iterator
| parallel [(chunk_specification)] [aspect_specification]
for loop_parameter_specification
| parallel [(chunk_specification)] [aspect_specification]
for iterator_specification
3.1/5
chunk_specification ::=
integer_simple_expression
| defining_identifier in discrete_subtype_definition
4/5
loop_parameter_specification ::=
defining_identifier in [reverse] discrete_subtype_definition
[iterator_filter]
4.1/5
iterator_filter ::= when condition
5
If a loop_statement has a loop_statement_identifier, then the identifier shall be repeated after the end loop; otherwise, there shall not be an identifier after the end loop.
5.1/5
An iteration_scheme that begins with the reserved word parallel shall not have the reserved word reverse in its loop_parameter_specification.

#### Name Resolution Rules

5.2/5
In a chunk_specification that is an integer_simple_expression, the integer_simple_expression is expected to be of any integer type.

#### Static Semantics

6/5
A loop_parameter_specification declares a loop parameter, which is an object whose subtype (and nominal subtype) is that defined by the discrete_subtype_definition.
6.1/5
In a chunk_specification that has a discrete_subtype_definition, the chunk_specification declares a chunk parameter object whose subtype (and nominal subtype) is that defined by the discrete_subtype_definition.

#### Dynamic Semantics

6.2/5
The filter of an iterator construct (a loop_parameter_specification, iterator_specification, or procedural_iterator) is defined to be satisfied when there is no iterator_filter for the iterator construct, or when the condition of the iterator_filter evaluates to True for a given iteration of the iterator construct.
6.3/5
If a sequence_of_statements of a loop_statement with an iterator construct is said to be conditionally executed, then the statements are executed only when the filter of the iterator construct is satisfied.
6.4/5
The loop iterators loop_parameter_specification and iterator_specification can also be used in contexts other than loop_statements (for example, see 4.3.5 and 4.5.8). In such a context, the iterator conditionally produces values in the order specified for the associated construct below or in 5.5.2. The values produced are the values given to the loop parameter when the filter of the iterator construct is satisfied for that value. No value is produced when the condition of an iterator_filter evaluates to False.
7/5
For the execution of a loop_statement, the sequence_of_statements is executed zero or more times, until the loop_statement is complete. The loop_statement is complete when a transfer of control occurs that transfers control out of the loop, or, in the case of an iteration_scheme, as specified below.
8
For the execution of a loop_statement with a while iteration_scheme, the condition is evaluated before each execution of the sequence_of_statements; if the value of the condition is True, the sequence_of_statements is executed; if False, the execution of the loop_statement is complete.
8.1/5
If the reserved word parallel is present in the iteration_scheme of a loop_statement (a parallel loop), the iterations are partitioned into one or more chunks, each with its own separate logical thread of control (see Clause 9). If a chunk_specification is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the chunk_specification is an integer_simple_expression, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a discrete_subtype_definition is present, the elaboration elaborates the discrete_subtype_definition, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the chunk_specification, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised.
9/5
For the execution of a loop_statement that has an iteration_scheme including a loop_parameter_specification, after elaborating the chunk_specification and aspect_specification, if any, the loop_parameter_specification is elaborated. This elaborates the discrete_subtype_definition, which defines the subtype of the loop parameter. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is conditionally executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a sequential loop), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. In the absence of a transfer of control, the associated parallel construct of a loop_parameter_specification is complete when all of its logical threads of control are complete.
10/5
If a chunk_specification with a discrete_subtype_definition is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters.
11/5
Whether or not a chunk_specification is present in a parallel loop, the total number of iterations of the loop represents an upper bound on the number of logical threads of control devoted to the loop.
12/5
For details about the execution of a loop_statement with the iteration_scheme including an iterator_specification, see 5.5.2. For details relating to a procedural_iterator, see 5.5.3.
13/5
NOTE 1 A loop parameter declared by a loop_parameter_specification is a constant; it cannot be updated within the sequence_of_statements of the loop (see 3.3).
14/5
NOTE 2 No separate object_declaration is expected for a loop parameter, since the loop parameter is automatically declared by the loop_parameter_specification. The scope of a loop parameter extends from the loop_parameter_specification to the end of the loop_statement, and the visibility rules are such that a loop parameter is only visible within the sequence_of_statements of the loop.
15/5
NOTE 3 The discrete_subtype_definition of a for loop is elaborated just once. Use of the reserved word reverse does not alter the discrete subtype defined, so that the following iteration_schemes are not equivalent; the first has a null range.
16
for J in reverse 1 .. 0
for J in 0 .. 1

#### Examples

17
Example of a loop statement without an iteration scheme:
18
loop
Get(Current_Character);
exit when Current_Character = '*';
end loop;
19
Example of a loop statement with a while iteration scheme:
20
while Bid(N).Price < Cut_Off.Price loop
Record_Bid(Bid(N).Price);
N := N + 1;
end loop;
21
Example of a loop statement with a for iteration scheme:
22
for J in Buffer'Range loop -- works even with a null range
if Buffer(J) /= Space then
Put(Buffer(J));
end if;
end loop;
23
Example of a loop statement with a name:
24
Summation:
while Next /= Head loop -- see 3.10.1
Sum := Sum + Next.Value;
Next := Next.Succ;
end loop Summation;
25/5
Example of a simple parallel loop:
26/5
-- see 3.6
parallel
for I in Grid'Range(1) loop
Grid(I, 1) := (for all J in Grid'Range(2) => Grid(I,J) = True);
end loop;
27/5
Example of a parallel loop with a chunk specification:
28/5
declare
subtype Chunk_Number is Natural range 1 .. 8;
29/5
Partial_Sum,
Partial_Max : array (Chunk_Number) of Natural := (others => 0);
Partial_Min : array (Chunk_Number) of Natural :=
(others => Natural'Last);
30/5
begin
parallel (Chunk in Chunk_Number)
for I in Grid'Range(1) loop
declare
True_Count : constant Natural :=
[for J in Grid'Range(2) =>
(if Grid (I, J) then 1 else 0)]'Reduce("+",0);
begin
Partial_Sum (Chunk) := @ + True_Count;
Partial_Min (Chunk) := Natural'Min(@, True_Count);
Partial_Max (Chunk) := Natural'Max(@, True_Count);
end;
end loop;
31/5
Put_Line
("Total=" & Partial_Sum'Reduce("+", 0)'Image &
", Min=" & Partial_Min'Reduce(Natural'Min, Natural'Last)'Image &
", Max=" & Partial_Max'Reduce(Natural'Max, 0)'Image);
end;
32/5
For an example of an iterator_filter, see 4.5.8.

Ada 2005 and 2012 Editions sponsored in part by Ada-Europe