5.5 Loop Statements
Syntax
Name Resolution Rules
Static Semantics
Dynamic Semantics
Term entry: iterator
filter — construct that is used to restrict the elements produced
by an iteration to those for which a boolean condition evaluates to True
{
AI12-0251-1}
{
AI12-0294-1}
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.
{
AI05-0139-2}
{
AI05-0262-1}
{
AI12-0071-1}
{
AI12-0119-1}
{
AI12-0250-1}
{
AI12-0251-1}
{
AI12-0294-1}
{
AI12-0355-2}
{
AI12-0416-1}
For
the execution of a
loop_statement
that has an with the
iteration_scheme
including a being
for loop_parameter_specification,
after elaborating the chunk_specification
and aspect_specification,
if any, the
loop_parameter_specification
is
first elaborated. This
elaboration
creates the loop parameter and 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 predicate
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. These 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.
To be honest: {
AI12-0294-1}
This wording does not describe when the loop parameter
object(s) are created. That creation has no side-effects (other than
possibly raising Storage_Error, but anything can do that), so we simplified
the wording by leaving it out. Each object has to be created before any
iteration that depends on it starts, but we do not (for instance) require
that the objects are all created at once at the start of the loop, nor
that the objects are created after the elaboration of the discrete_subtype_definition.
This paragraph
was deleted.Ramification: {
AI12-0294-1}
The order of creating the loop parameter and evaluating
the discrete_subtype_definition
doesn't matter, since the creation of the loop parameter has no side
effects (other than possibly raising Storage_Error, but anything can
do that).
{
AI05-0262-1}
The predicate (if any) necessarily has to be a static predicate as a
dynamic predicate is explicitly disallowed — see
3.2.4.
Reason: {
AI05-0262-1}
If there is a predicate, the loop still visits the values in the order
of the underlying base type; the order of the values in the predicate
is irrelevant. This is the case so that the following loops have the
same sequence of calls and parameters on procedure Call for any subtype
S:
for I in S loop
Call (I);
end loop;
for I in S'Base loop
if I in S then
Call (I);
end if;
end loop;
Discussion: {
AI12-0416-1}
The rules for completing a parallel construct when
there is a transfer of control are given in 5.1.
{
AI12-0251-1}
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.
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.
for J in reverse 1 .. 0
for J in 0 .. 1
Examples
Example of a loop
statement without an iteration scheme:
loop
Get(Current_Character);
exit when Current_Character = '*';
end loop;
Example of a loop
statement with a while iteration scheme:
while Bid(N).Price < Cut_Off.Price loop
Record_Bid(Bid(N).Price);
N := N + 1;
end loop;
Example of a loop
statement with a for iteration scheme:
for J in Buffer'Range loop -- works even with a null range
if Buffer(J) /= Space then
Put(Buffer(J));
end if;
end loop;
Example of a loop
statement with a name:
Summation:
while Next /= Head
loop --
see 3.10.1
Sum := Sum + Next.Value;
Next := Next.Succ;
end loop Summation;
-- 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;
{
AI12-0312-1}
Example of a parallel loop with a chunk specification:
declare
subtype Chunk_Number is Natural range 1 .. 8;
Partial_Sum,
Partial_Max : array (Chunk_Number) of Natural := (others => 0);
Partial_Min : array (Chunk_Number) of Natural :=
(others => Natural'Last);
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;
{
AI12-0386-1}
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;
Wording Changes from Ada 83
Wording Changes from Ada 2005
Extensions to Ada 2012
Wording Changes from Ada 2012
{
AI12-0071-1}
Corrigendum: Updated wording of loop execution
to use the new term "satisfies the predicates" (see 3.2.4).
{
AI12-0061-1}
Added text so that the nominal subtype of a loop
parameter is clearly defined.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe