5.5.3 Procedural Iterators
{
AI12-0189-1}
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
Name Resolution Rules
Legality Rules
Static Semantics
{
AI12-0344-1}
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.
{
AI12-0189-1}
{
AI12-0326-2}
{
AI12-0344-1}
The following aspects may be specified for a callable
entity S that has exactly one formal parameter of an anonymous
access-to-subprogram type:
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.
Reason: An entry
does not allow exit, because implementing a transfer of control out of
a task or protected entry creates unnecessarily complex dynamic semantics.
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].
Aspect Description
for Allows_Exit: An
indication of whether a subprogram will operate correctly for arbitrary
transfers of control.
Ramification: A
subprogram that does not need cleanup satisfies the requirements, and
thus can specify Allows_Exit as True. If a subprogram S allows
exit, it cannot expect to get control other than via finalization if
the loop body procedure initiates a transfer of control as part of a
procedural_iterator.
In particular, exception handlers in S, even when others
handlers, will not be executed when a transfer of control occurs. The
mechanism that the implementation uses to implement such transfers of
control needs to avoid triggering exception handlers.
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.
{
AI12-0189-1}
{
AI12-0442-1}
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.
Aspect Description
for Parallel_Iterator: An
indication of whether a subprogram may use multiple threads of control
to invoke a loop body procedure.
Reason: Permitting
exit from a parallel procedural iterator introduces additional semantic
and implementation complexity.
Legality Rules
{
AI12-0189-1}
{
AI12-0326-2}
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.
Ramification: Since
an entry never allows exit, attempting to implement an allows exit subprogram
with a task or protected entry is always illegal. However, the Parallel_Iterator
aspect can be applied to an entry, so a subprogram with the Parallel_Iterator
aspect True can be implemented by an entry.
{
AI12-0326-2}
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).
Reason: An accept_statement
is not allowed in a procedure (see 9.5.2), it has to be directly in a
task_body.
Since the loop body here is implemented as a procedure, we can't allow
accept_statements
there, either, even if the loop itself is directly in a task_body.
Dynamic Semantics
Proof: The stated
dynamic semantics are implied by the static semantics given above and
the bounded errors given below.
Bounded (Run-Time) Errors
{
AI12-0326-2}
{
AI12-0445-1}
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.
{
AI12-0326-2}
{
AI12-0445-1}
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.
Discussion: {
AI12-0326-2}
Other Ada rules are still in effect for the allows
exit subprogram A, of course. For instance, if a transfer of control
causes finalization which raises an exception, Program_Error will be
propagated by A (rather than the transfer of control). In such
a case, the bounded error above would still apply. Another example is
the case where an unrelated task is waiting on the normal completion
of the loop body procedure call in A. Such a task might end up
waiting forever if a transfer of control happens (this is a deadlock
situation). This case does not require additional wording, as the same
thing would happen if an exception is propagated from the loop body procedure
or if A executed a transfer of control (such as a return statement).
Examples
for (C : Cursor) of My_Map.Iterate loop
Put_Line (My_Key_Type'Image (Key (C)) & " => " &
My_Element_Type'Image (Element (C)));
end loop;
-- The above is equivalent to:
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;
for (Name, Val) of Ada.Environment_Variables.Iterate(<>) loop
-- "(<>)" is optional because it is the last parameter
Put_Line (Name & " => " & Val);
end loop;
-- The above is equivalent to:
declare
procedure P (Name : String; Val : String) is
begin
Put_Line (Name & " => " & Val);
end P;
begin
Ada.Environment_Variables.Iterate (P'Access);
end;
Extensions to Ada 2012
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe