5.5.2 Generalized Loop Iteration
Syntax
Name Resolution Rules
For the first form of 
iterator_specification, 
called a 
generalized iterator,
 
the expected type for the 
iterator_name 
is any iterator type.
 For the second form of 
iterator_specification, 
the expected type for the 
iterable_name 
is any array or iterable container type.
 If the 
iterable_name 
denotes an array object, the 
iterator_specification 
is called an 
array component iterator;
 
otherwise it is called a 
container element iterator.
 
 
Legality Rules
If the reserved word 
reverse appears, the 
iterator_specification 
is a 
reverse iterator. 
If the 
iterator_specification 
is for a parallel construct, the 
iterator_specification 
is a 
parallel iterator.
 
Otherwise, it is a 
forward iterator.
 
Forward and reverse iterators are collectively called 
sequential 
iterators.
 In a reverse generalized 
iterator, the 
iterator_name 
shall be of a reversible iterator type. In a parallel generalized iterator, 
the 
iterator_name 
shall be of a parallel iterator type. In a reverse container element 
iterator, the default iterator type for the type of the 
iterable_name 
shall be a reversible iterator type. In a parallel container element 
iterator, the default iterator type for the type of the 
iterable_name 
shall be of a parallel iterator type.
 
In a container element iterator whose 
iterable_name 
has type 
T, if the 
iterable_name 
denotes a constant or the Variable_Indexing aspect is not specified for 
T, then the Constant_Indexing aspect shall be specified for 
T.
 
 The 
iterator_name 
or 
iterable_name 
of an 
iterator_specification 
shall not denote a subcomponent that depends on discriminants of an object 
whose nominal subtype is unconstrained, unless the object is known to 
be constrained.
 
 A container element iterator is illegal if the call 
of the default iterator function that creates the loop iterator (see 
below) is illegal.
 A generalized iterator is illegal if the iteration 
cursor subtype of the 
iterator_name 
is a limited type at the point of the generalized iterator. A container 
element iterator is illegal if the default cursor subtype of the type 
of the 
iterable_name 
is a limited type at the point of the container element iterator.
 
Static Semantics
An 
iterator_specification 
declares a 
loop parameter.
 In a generalized 
iterator, an array component iterator, or a container element iterator, 
if a 
loop_parameter_subtype_indication 
is present, it determines the nominal subtype of the loop parameter. 
In a generalized iterator, if a 
loop_parameter_subtype_indication 
is not present, the nominal subtype of the loop parameter is the iteration 
cursor subtype. In an array component iterator, if a 
loop_parameter_subtype_indication 
is not present, the nominal subtype of the loop parameter is the component 
subtype of the type of the 
iterable_name. 
In a container element iterator, if a 
loop_parameter_subtype_indication 
is not present, the nominal subtype of the loop parameter is the default 
element subtype for the type of the 
iterable_name.
 
In a generalized iterator, the loop parameter is 
a constant. In an array component iterator, the loop parameter is a constant 
if the 
iterable_name 
denotes a constant; otherwise it denotes a variable. In a container element 
iterator, the loop parameter is a constant if the 
iterable_name 
denotes a constant, or if the Variable_Indexing aspect is not specified 
for the type of the 
iterable_name; 
otherwise it is a variable.
 
Dynamic Semantics
For a sequential generalized iterator, the loop parameter 
is created, the 
iterator_name 
is evaluated, and the denoted iterator object becomes the 
loop iterator.
 
In a forward generalized iterator, the operation First of the iterator 
type is called on the loop iterator, to produce the initial value for 
the loop parameter. If the result of calling Has_Element on the initial 
value is False, then the execution of the 
loop_statement 
is complete. Otherwise, the 
sequence_of_statements 
is conditionally executed and then the Next operation of the iterator 
type is called with the loop iterator and the current value of the loop 
parameter to produce the next value to be assigned to the loop parameter. 
This repeats until the result of calling Has_Element on the loop parameter 
is False, or the loop is left as a consequence of a transfer of control. 
For a reverse generalized iterator, the operations Last and Previous 
are called rather than First and Next.
 
  For a parallel generalized iterator, the 
chunk_specification, 
if any, of the associated parallel construct, is first elaborated, to 
determine the maximum number of chunks (see 
5.5), 
and then the operation Split_Into_Chunks of the iterator type is called, 
with the determined maximum passed as the Max_Chunks parameter, specifying 
the upper bound for the number of loop parameter objects (and the number 
of logical threads of control) to be associated with the iterator. In 
the absence of a 
chunk_specification, 
the maximum number of chunks is determined in an implementation-defined 
manner.
 
  Upon return from Split_Into_Chunks, the actual 
number of chunks for the loop is determined by calling the Chunk_Count 
operation of the iterator, at which point one logical thread of control 
is initiated for each chunk, with an associated chunk index in the range 
from one to the actual number of chunks.
  Within each logical thread of control, a loop parameter 
is created. If a 
chunk_specification 
with a 
discrete_subtype_definition 
is present in the associated parallel construct, then a chunk parameter 
is created and initialized with a value from the discrete subtype defined 
by the 
discrete_subtype_definition, 
so that the order of the chosen chunk parameter values correspond to 
the order of the chunk indices associated with the logical threads of 
control. The operation First of the iterator type that has a Chunk parameter 
is called on the loop iterator, with Chunk initialized from the corresponding 
chunk index, to produce the initial value for the loop parameter. If 
the result of calling Has_Element on this initial value is False, then 
the execution of the logical thread of control is complete. Otherwise, 
the 
sequence_of_statements 
is conditionally executed, and then the Next operation of the iterator 
type that has a Chunk parameter is called with the loop iterator, the 
current value of the loop parameter, and the corresponding chunk index, 
to produce the next value to be assigned to the loop parameter. This 
repeats until the result of calling Has_Element on the loop parameter 
is False, or the associated parallel construct is left as a consequence 
of a transfer of control.
 
  In the absence of a transfer of control, the associated 
parallel construct of a parallel generalized iterator is complete when 
all of its logical threads of control are complete.
For an array component iterator, the 
chunk_specification 
of the associated parallel construct, if any, is first elaborated to 
determine the maximum number of chunks (see 
5.5), 
and then the 
iterable_name 
is evaluated and the denoted array object becomes the 
array for the 
loop.
 If the array for the loop is a null array, 
then the execution of the 
loop_statement 
is complete. Otherwise, the 
sequence_of_statements 
is conditionally executed with the loop parameter denoting each component 
of the array for the loop, using a 
canonical order of components,
 
which is last dimension varying fastest (unless the array has convention 
Fortran, in which case it is first dimension varying fastest). For a 
forward array component iterator, the iteration starts with the component 
whose index values are each the first in their index range, and continues 
in the canonical order. For a reverse array component iterator, the iteration 
starts with the component whose index values are each the last in their 
index range, and continues in the reverse of the canonical order. For 
a parallel array component iterator, the iteration is broken up into 
contiguous chunks of the canonical order, such that all components are 
covered with no overlaps; each chunk has its own logical thread of control 
with its own loop parameter and iteration within each chunk is in the 
canonical order. The number of chunks is implementation defined, but 
is limited in the presence of a 
chunk_specification 
to the determined maximum. The loop iteration proceeds until the 
sequence_of_statements 
has been conditionally executed for each component of the array for the 
loop, or until the loop is left as a consequence of a transfer of control.
 
  If a 
chunk_specification 
with a 
discrete_subtype_definition 
is present in the associated parallel construct, then the logical thread 
of control associated with a given chunk has a 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 
in the canonical order of the starting array components for the chunks.
 
For a container element iterator, the 
chunk_specification 
of the associated parallel construct, if any, is first elaborated to 
determine the maximum number of chunks (see 
5.5), 
and then the 
iterable_name 
is evaluated. If the container type has Iterator_View specified, an object 
of the Iterator_View type is created with the discriminant referencing 
the iterable container object denoted by the 
iterable_name. 
This is the 
iterable container object for the loop. Otherwise, 
the iterable container object denoted by the 
iterable_name 
becomes the iterable container object for the loop.
 
The default iterator function for the type of the iterable container 
object for the loop is called on the iterable container object and the 
result is the 
loop iterator.
 For a sequential 
container element iterator, an object of the default cursor subtype is 
created (the 
loop cursor).
 For a parallel 
container element iterator, each chunk of iterations will have its own 
loop cursor, again of the default cursor subtype.
 
A container element iterator then proceeds as described 
above for a generalized iterator, except that each reference to a loop 
parameter is replaced by a reference to the corresponding loop cursor. 
For a container element iterator, the loop parameter for each iteration 
instead denotes an indexing (see 
4.1.6) into 
the iterable container object for the loop, with the only parameter to 
the indexing being the value of the loop cursor for the given iteration. 
If the loop parameter is a constant (see above), then the indexing uses 
the default constant indexing function for the type of the iterable container 
object for the loop; otherwise it uses the default variable indexing 
function.
 
Any exception propagated by the execution of a generalized 
iterator or container element iterator is propagated by the immediately 
enclosing loop statement.
Examples
Example of a parallel 
generalized loop over an array:
parallel
for Element 
of Board 
loop  -- 
See 3.6.1.
   Element := Element * 2.0; -- 
Double each element of Board, a two-dimensional array.
end loop;
 
For examples of use of generalized iterators, 
see A.18.33 and the corresponding container 
packages in A.18.2 and A.18.3. 
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe