Overview of Ada 2022
Jeff Cousins
Contents   Index   Search   Previous   Next 

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.

Contents   Index   Search   Previous   Next 
© 2021, 2022 Jeff Cousins