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