Ada Reference Manual (Ada 2022) — Legal Information

# 5.5.3 Procedural Iterators

1/5
A procedural_iterator invokes a user-defined procedure, passing in the body of the enclosing loop_statement as a parameter of an anonymous access-to-procedure type, to allow the loop body to be executed repeatedly as part of the invocation of the user-defined procedure.

#### Syntax

2/5
procedural_iterator ::=
iterator_parameter_specification of iterator_procedure_call
[iterator_filter]
3/5
iterator_parameter_specification ::=
formal_part
| (defining_identifier{, defining_identifier})
4/5
iterator_procedure_call ::=
procedure_name
| procedure_prefix iterator_actual_parameter_part
5/5
iterator_actual_parameter_part ::=
(iterator_parameter_association {, iterator_parameter_association})
6/5
iterator_parameter_association ::=
parameter_association
| parameter_association_with_box
7/5
parameter_association_with_box ::=
[ formal_parameter_selector_name => ] <>
8/5
At most one iterator_parameter_association within an iterator_actual_parameter_part shall be a parameter_association_with_box.

#### Name Resolution Rules

9/5
The name or prefix given in an iterator_procedure_call shall resolve to denote a callable entity C (the iterating procedure) that is a procedure, or an entry renamed as (viewed as) a procedure. When there is an iterator_actual_parameter_part, the prefix can be an implicit_dereference of an access-to-subprogram value.
10/5
An iterator_procedure_call without a parameter_association_with_box is equivalent to one with an iterator_actual_parameter_part with an additional parameter_association_with_box at the end, with the formal_parameter_selector_name identifying the last formal parameter of the callable entity denoted by the name or prefix.
11/5
An iterator_procedure_call shall contain at most one iterator_parameter_association for each formal parameter of the callable entity C. Each formal parameter without an iterator_parameter_association shall have a default_expression (in the profile of the view of C denoted by the name or prefix).
12/5
The formal parameter of the callable entity C associated with the parameter_association_with_box shall be of an anonymous access-to-procedure type A.

#### Legality Rules

13/5
The anonymous access-to-procedure type A shall have at least one formal parameter in its parameter profile. If the iterator_parameter_specification is a formal_part, then this formal_part shall be mode conformant with that of A. If the iterator_parameter_specification is a list of defining_identifiers, the number of formal parameters of A shall be the same as the length of this list.
14/5
If the name or prefix given in an iterator_procedure_call denotes an abstract subprogram, the subprogram shall be a dispatching subprogram.

#### Static Semantics

15/5
A loop_statement with an iteration_scheme that has a procedural_iterator is equivalent to a local declaration of a procedure P followed by a procedure_call_statement that is formed from the iterator_procedure_call by replacing the <> of the parameter_association_with_box with P'Access. The formal_part of the locally declared procedure P is formed from the formal_part of the anonymous access-to-procedure type A, by replacing the identifier of each formal parameter of this formal_part with the identifier of the corresponding formal parameter or element of the list of defining_identifiers given in the iterator_parameter_specification. The body of P consists of the conditionally executed sequence_of_statements. The procedure P is called the loop body procedure.
16/5
In a procedural iterator, the Parallel_Calls aspect (see 9.10.1) of the loop body procedure is True if the reserved word parallel occurs in the corresponding loop statement, and False otherwise.
17/5
The following aspects may be specified for a callable entity S that has exactly one formal parameter of an anonymous access-to-subprogram type:
18/5
Allows_Exit
The Allows_Exit aspect is of type Boolean. The specified value shall be static. The Allows_Exit aspect of an inherited primitive subprogram is True if Allows_Exit is True either for the corresponding subprogram of the progenitor type or for any other inherited subprogram that it overrides. If not specified or inherited as True, the Allows_Exit aspect of a callable entity is False. For an entry, only a confirming specification of False is permitted for the Allows_Exit aspect.
19/5
Specifying the Allows_Exit aspect to be True for a subprogram indicates that the subprogram allows exit, meaning that it is prepared to be completed by arbitrary transfers of control from the loop body procedure, including propagation of exceptions. A subprogram for which Allows_Exit is True should use finalization as appropriate rather than exception handling to recover resources and make any necessary final updates to data structures.
20/5
Parallel_Iterator
The Parallel_Iterator aspect is of type Boolean. The specified value shall be static. The Parallel_Iterator aspect of an inherited primitive subprogram is True if Parallel_Iterator is True either for the corresponding subprogram of the progenitor type or for any other inherited subprogram that it overrides. If not specified or inherited as True, the Parallel_Iterator aspect of a callable entity is False.
21/5
Specifying the Parallel_Iterator aspect to be True for a callable entity indicates that the entity is allowed to invoke the loop body procedure from multiple distinct logical threads of control. The Parallel_Iterator aspect for a subprogram shall be statically False if the subprogram allows exit.

#### Legality Rules

22/5
If a callable entity overrides an inherited dispatching subprogram that allows exit, the overriding callable entity also shall allow exit. If a callable entity overrides an inherited dispatching subprogram that has a True Parallel_Iterator aspect, the overriding callable entity also shall have a True Parallel_Iterator aspect.
23/5
A loop_statement with a procedural_iterator as its iteration_scheme shall begin with the reserved word parallel if and only if the callable entity identified in the iterator_procedure_call has a Parallel_iterator aspect of True.
24/5
If the actual parameter of an anonymous access-to-subprogram type, passed in an explicit call of a subprogram for which the Parallel_Iterator aspect is True, is of the form P'Access, the designated subprogram P shall have a Parallel_Calls aspect True (see 9.10.1).
25/5
The sequence_of_statements of a loop_statement with a procedural_iterator as its iteration_scheme shall contain an exit_statement, return statement, goto_statement, or requeue_statement that leaves the loop only if the callable entity associated with the procedural_iterator allows exit.
26/5
The sequence_of_statements of a loop_statement with a procedural_iterator as its iteration_scheme shall not contain an accept_statement whose entry_declaration occurs outside the loop_statement.

#### Dynamic Semantics

27/5
For the execution of a loop_statement with an iteration_scheme that has a procedural_iterator, the procedure denoted by the name or prefix of the iterator_procedure_call (the iterating procedure) is invoked, passing an access value designating the loop body procedure as a parameter. The iterating procedure then calls the loop body procedure zero or more times and returns, whereupon the loop_statement is complete. If the parallel reserved word is present, the iterating procedure is allowed to invoke the loop body procedure from multiple distinct logical threads of control. The aspect_specification, if any, is elaborated prior to the invocation of the iterating procedure.

#### Bounded (Run-Time) Errors

28/5
If the callable entity identified in the iterator_procedure_call allows exit, then it is a bounded error for a call of the loop body procedure to be performed from within an abort-deferred operation (see 9.8), unless the entire loop_statement was within the same abort-deferred operation. If detected, Program_Error is raised at the point of the call; otherwise, a transfer of control from the sequence_of_statements of the loop_statement will not necessarily terminate the loop_statement, and the loop body procedure can be called again.
29/5
If a loop_statement with the procedural_iterator as its iteration_scheme (see 5.5) does not begin with the reserved word parallel, it is a bounded error if the loop body procedure is invoked from a different logical thread of control than the one that initiates the loop_statement. If detected, Program_Error is raised; otherwise, conflicts associated with concurrent executions of the loop body procedure can occur without being detected by the applicable conflict check policy (see 9.10.1). Furthermore, propagating an exception or making an attempt to exit in the presence of multiple threads of control will not necessarily terminate the loop_statement, deadlock can occur, or the loop body procedure can be called again.

#### Examples

30/5
Example of iterating over a map from My_Key_Type to My_Element_Type (see A.18.4):
31/5
for (C : Cursor) of My_Map.Iterate loop
Put_Line (My_Key_Type'Image (Key (C)) & " => " &
My_Element_Type'Image (Element (C)));
end loop;
32/5
-- The above is equivalent to:
33/5
declare
procedure P (C : Cursor) is
begin
Put_Line (My_Key_Type'Image (Key (c)) & " => " &
My_Element_Type'Image (Element (C)));
end P;
begin
My_Map.Iterate (P'Access);
end;
34/5
Example of iterating over the environment variables (see A.17):
35/5
for (Name, Val) of Ada.Environment_Variables.Iterate(<>) loop
-- "(<>)" is optional because it is the last parameter
Put_Line (Name & " => " & Val);
end loop;
36/5
-- The above is equivalent to:
37/5
declare
procedure P (Name : String; Val : String) is
begin
Put_Line (Name & " => " & Val);
end P;
begin
Ada.Environment_Variables.Iterate (P'Access);
end;

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