Overview of Ada 2022
4.4 Loop-body as anonymous procedure
Loop-body as anonymous procedure (AI12-0189)
allows a loop body to be used to specify the implementation of a procedure
to be passed as the actual for an access-to-subprogram parameter, when
used in the context of a special kind of for loop statement, whose iterator
specification is given by a procedure iterator (see RM
5.5.3).
This can be used for iterating over directories and
environment variables, or iterating through a map-like container over
the keys. Dedicated mechanisms were proposed for these (
AI12-0009
and
AI12-0188,
respectively), but it was considered more useful to add a more general
mechanism.
For example, to do
something for each environment variable, in Ada 2012 the user can write
a procedure and pass a pointer to it to the Iterate
procedure of Ada.Environment_Variables, as
in:
procedure Print_One
(Name : in String;
Value : in String) is
begin
Put_Line (Name & "=" & Value);
end Print_One;
...
Ada.Environment_Variables.Iterate (Print_One'Access);
In Ada 2022, instead
of explicitly writing a procedure, one can use the of form of
a for loop, and the body of the loop is automatically turned into
an anonymous procedure that is passed to the Iterate
procedure of Ada.Environment_Variables, as
in:
for (Name, Value) of Ada.Environment_Variables.Iterate (<>) loop
-- "(<>)" is optional because it is the last parameter
Put_Line (Name & " => " & Value);
end loop;
An
exit,
return,
goto, or other
transfer of control out of the loop is only allowed if the iterator procedure
has new aspect
Allows_Exit with value
True.
Even if
Allows_Exit is
False,
the loop can still end prematurely due to the propagation of an exception.
Allows_Exit aspect should be used on language-defined
subprograms (AI12-0286)
adds aspect
Allows_Exit to the language-defined
subprograms, where appropriate, i.e. to the
Search
procedure of
Ada.Directories, and the
Iterate
procedure of
Ada.Environment_Variables (see
below, and used in the examples above and below).
procedure Iterate
(Process : not null access procedure
(Name, Value : in String))
with Allows_Exit;
This allows an early
exit when iterating over the environment variables, as in this more sophisticated
variant of the previous example:
for (Name, Value) of Ada.Environment_Variables.Iterate (<>) loop
if Bounded_Strings.Index
(Source => Bounded_Strings.To_Bounded_String (Name),
Pattern => "Path",
From => Name'First) /= 0 then
-- Found an environment variable with name "*Path*"
Put_Line (Name & " => " & Value);
exit; -- Exit loop now
end if;
end loop;
Bounded errors associated with procedural iterators
(AI12-0326-2)
extends
AI12-0189
to make it a bounded error for an
Allows_Exit
subprogram to call the loop body procedure from an abort-deferred operation
(unless the whole
loop_statement was within
this same abort-deferred operation), as this would interfere with implementing
a transfer of control.
It is also adds the reserved word parallel
to the syntax for procedural iterators, and makes it a bounded error
to call a loop body procedure from multiple logical threads of control
unless parallel is specified.
Note that if Allows_Exit
is True then this precludes calling the loop
body procedure from a parallel iterator.
It is anticipated that (internally) early exit will
be implemented using exception handling.
Procedural iterator aspects
(AI12-0344)
says that if restriction
No_Exceptions is
in force then an early exit will not be allowed, regardless of whether
Allows_Exit is
True.
If the reserved word
parallel occurs in the
loop statement for a loop body procedure then the
Parallel_Calls
aspect (see
2.2, “
Nonblocking
and data race checks”) is implicitly set for the loop body
procedure.
© 2021, 2022 Jeff Cousins