CVS difference for ai12s/ai12-0189-1.txt

Differences between 1.7 and version 1.8
Log of other versions for file ai12s/ai12-0189-1.txt

--- ai12s/ai12-0189-1.txt	2017/01/14 02:55:52	1.7
+++ ai12s/ai12-0189-1.txt	2017/10/12 03:22:37	1.8
@@ -1,4 +1,5 @@
-!standard 5.5.2(2/3)                                  16-10-04  AI12-0189-1/03
+!standard 5.5(3/3)                                    17-10-11  AI12-0189-1/04
+!standard 5.5.3(0)
 !class Amendment 16-06-02
 !status work item 16-06-02
 !status received 16-05-06
@@ -95,8 +96,157 @@
 
 !wording
 
-** TBD.
+Modify 5.5(3/3):
+
+  iteration_scheme ::= WHILE condition
+   | FOR loop_parameter_specification
+   | FOR iterator_specification
+  {| FOR procedural_iterator}  -- "{}" mean "add" here
+
+Add a section 5.5.3:
+
+5.5.3 Procedural Iterators
+
+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
+
+   procedural_iterator ::=
+     iterator_parameter_specification OF iterator_procedure_call
+
+   iterator_parameter_specification ::=
+       formal_part
+     | (identifier{, identifier})
+
+   iterator_procedure_call ::=
+       /procedure/_name
+     | /procedure_/prefix iterator_actual_parameter_part
+
+   iterator_actual_parameter_part ::=
+     (iterator_parameter_association {, iterator_parameter_association})
+
+   iterator_parameter_association ::= parameter_association
+     | parameter_association_with_box
+
+   parameter_association_with_box ::=
+     [ /formal_parameter_/selector_name => ] <>
+
+At most one iterator_parameter_association within an
+iterator_actual_parameter_part shall be a parameter_association_with_box.
+
+     Name Resolution Rules
+
+The name or prefix given in an iterator_procedure_call shall resolve to denote a
+callable entity C that is a procedure, or an entry renamed as (viewed as) a
+procedure. The name or prefix shall not resolve to denote an abstract subprogram
+unless it is also a dispatching subprogram. [Redundant: When there is an
+iterator_actual_parameter_part, the prefix can be an implicit_dereference of an
+access-to-subprogram value.]
+
+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.
+
+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). [Redundant: This rule is an overloading rule (see 8.6).]
+
+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
+
+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 identifiers, the number of
+formal parameters of /A/ shall be the same as the length of this list.
+
+     Static Semantics
+
+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 identifiers given in
+the iterator_parameter_specification.
+
+The following aspect may be specified for a subprogram or entry S that has at
+least one formal parameter of an anonymous access-to-subprogram type:
+
+Exit_Exception
+   This aspect is specified by a name that denotes an exception E, or by
+   the literal NULL.  If not the literal NULL, this indicates that the
+   subprogram or entry S will terminate its execution and propagate the
+   exception E if E is propagated by an invocation of
+   a procedure denoted by a formal parameter of S having an anonymous
+   access-to-subprogram type.  The Exit_Exception of an inherited
+   primitive subprogram is that of the corresponding subprogram of the
+   progenitor type.  If not specified or inherited, the Exit_Exception aspect
+   of a subprogram or entry is the NULL literal.
+
+       Legality Rules
+
+If a subprogram or entry overrides an inherited subprogram that has an
+Exit_Exception aspect that is not the NULL literal, it shall specify the same
+exception for its Exit_Exception aspect.
+
+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 C has an Exit_Exception aspect that is not the NULL literal.
+
+    Examples
+
+Example of iterating over a map from My_Key_Type to My_Element_Type (see
+A.18.4):
+
+   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.Iterator (P'Access);
+   end;
+
+Example of iterating over the environment variables (see A.17)
+
+   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;
+
 !discussion
 
 This proposal is more general than the proposals in AI12-0009-1 and
@@ -110,11 +260,11 @@
        Put_Line (Name & " => " & Val);
 
     end loop;
-    
+
 We could add iterators to appropriate Container types that took an
 access-to-procedure with two parameters, namely Key and Value, to produce
 a container-element iterator that also makes the Keys available.  E.g.:
- 
+
    generic
       ...
    package Maps is
@@ -125,10 +275,10 @@
                  (Key : in Key_Type; Element : in Element_Type));
      ...
    end Maps
-               
+
    package My_Maps is new Maps(My_Key_Type, My_Element_Type, ...);
    ...
-   My_Map : My_Maps.Map;          
+   My_Map : My_Maps.Map;
    ...
    for (Key, Value) of My_Map.Iterate loop
       Put_Line (My_Key_Type'Image (Key) & " => " &
@@ -145,28 +295,25 @@
 
 
     ...
-    
+
     for (Key, Element) of My_Map.Var_Iterate loop
        if Key in Blah then
           Element.X := Z;
        end if;
        ...
     end loop;
-    
+
 Note that this approach eliminates the need for creating References for
 each element of the map, since we are using the normal semantics of
 in-out parameters to provide access to the appropriate element.
 
 We considered various implementation approaches for handling a transfer
 of control from the loop body, including the notion of a "private"
-exception which was not handled by "others."  We ultimately left it
-unspecified. Conceivably some future AI could try to define a portable
-mechanism, but this seems an unnecessary complication for this AI, and
-is almost certain to be less efficient than some implementation-specific
-approach, which can tap directly into the finalization mechanism used by
-the implementation.  We made it clear that the only way to specify "last
-wishes" for a routine calling a loop-body procedure was to use
-finalization.
+exception which was not handled by "others."  We ultimately decided to add an
+aspect Exit_Exception, that is required to be non null on the iterating
+procedure if you wish to perform a transfer of control.  The intent is that the
+compiler will raise and handle this exception to implement exit, goto, requeue,
+and return.
 
 !ASIS
 
@@ -1143,7 +1290,7 @@
 a special form of for-loop where the formal parameters act as the "loop
 variables" and the call on the iterating procedure has a "<>" to indicate
 where the loop-body-procedure should be "plugged in" to the call.  This
-grew out of a discussion at the ARG meeting in Vermont in October 2015. 
+grew out of a discussion at the ARG meeting in Vermont in October 2015.
 Look at an example in the AI to understand the usefulness of this...
 
 ****************************************************************
@@ -1197,11 +1344,11 @@
 From: Randy Brukardt
 Sent: Wednesday, October 5, 2016  5:02 PM
 
-> Here is an update.  I didn't make much of a change, except to decide 
-> that the transfer of control out of a loop body is permitted, the 
-> implementation has to support it, and the caller of a loop-body 
+> Here is an update.  I didn't make much of a change, except to decide
+> that the transfer of control out of a loop body is permitted, the
+> implementation has to support it, and the caller of a loop-body
 > procedure has to use finalization if they have any "last wishes"
-> they want honored if the loop-body procedures exits via a transfer of 
+> they want honored if the loop-body procedures exits via a transfer of
 > control.
 
 Having had months to think about it, I don't think the latter works.
@@ -1356,9 +1503,9 @@
 From: Tucker Taft
 Sent: Friday, October 7, 2016  6:26 PM
 
-> The critical point for me is that this tempting syntax should not be 
-> able to easily break existing subprograms for which it can be used. We 
-> cannot assume that a relatively unusual technique for "last wishes" 
+> The critical point for me is that this tempting syntax should not be
+> able to easily break existing subprograms for which it can be used. We
+> cannot assume that a relatively unusual technique for "last wishes"
 > has been used, and we cannot assume that any "last wishes" aren't
 > critical. ...
 
@@ -1371,7 +1518,7 @@
 I suppose we could define yet another aspect which must be specified on a
 subprogram with an access-to-procedure parameter, if it is to be used with
 a loop-body that contains a transfer of control out of the loop.  This would
-be the way for the implementor to say: 
+be the way for the implementor to say:
 "yes, I used finalization for last wishes, and so my routine can support a
 loop body with a transfer of control."
 
@@ -1391,16 +1538,16 @@
 
 > >> I'm not convinced yet. Should be a robust discussion.
 > >
-> > The critical point for me is that this tempting syntax should not be 
-> > able to easily break existing subprograms for which it can be used. 
+> > The critical point for me is that this tempting syntax should not be
+> > able to easily break existing subprograms for which it can be used.
 > > We cannot assume that a relatively unusual technique for "last wishes"
-> > has been used, and we cannot assume that any "last wishes" 
+> > has been used, and we cannot assume that any "last wishes"
 > > aren't critical. ...
-> 
-> For what it is worth, I just took a look at AdaCore's implementation 
-> of Ada.Containers.Vectors, for routines taking an "access procedure."  
-> All of them used finalization rather than exception handlers to ensure 
-> that the tampering bits were reset on exit.  So again, I am not 
+>
+> For what it is worth, I just took a look at AdaCore's implementation
+> of Ada.Containers.Vectors, for routines taking an "access procedure."
+> All of them used finalization rather than exception handlers to ensure
+> that the tampering bits were reset on exit.  So again, I am not
 > convinced that requiring such an approach is inappropriate.
 
 Requiring of whom? For language-defined libraries like containers, using
@@ -1416,11 +1563,11 @@
 mechanism is very complicated compared to a simple "others" handler with
 "raise;".)
 
-> I suppose we could define yet another aspect which must be specified 
-> on a subprogram with an access-to-procedure parameter, if it is to be 
-> used with a loop-body that contains a transfer of control out of the 
+> I suppose we could define yet another aspect which must be specified
+> on a subprogram with an access-to-procedure parameter, if it is to be
+> used with a loop-body that contains a transfer of control out of the
 > loop.  This would be the way for the implementor to say:
-> "yes, I used finalization for last wishes, and so my routine can 
+> "yes, I used finalization for last wishes, and so my routine can
 > support a loop body with a transfer of control."
 
 I don't think that is any help. Such an aspect can't be statically checked,
@@ -1428,7 +1575,7 @@
 to routines before the nice syntax can be used -- and most would apply it
 even if no finalization was used.
 
-> More generally, if your last wishes are "critical" then finalization 
+> More generally, if your last wishes are "critical" then finalization
 > seems the more robust approach.
 
 Surely. But how many Ada programmers know that? And even if the number is 80%,
@@ -1452,16 +1599,16 @@
 From: Tucker Taft
 Sent: Wednesday, December 21, 2016  9:13 AM
 
->> I suppose we could define yet another aspect which must be specified 
->> on a subprogram with an access-to-procedure parameter, if it is to be 
->> used with a loop-body that contains a transfer of control out of the 
+>> I suppose we could define yet another aspect which must be specified
+>> on a subprogram with an access-to-procedure parameter, if it is to be
+>> used with a loop-body that contains a transfer of control out of the
 >> loop.  This would be the way for the implementor to say:
->> "yes, I used finalization for last wishes, and so my routine can 
+>> "yes, I used finalization for last wishes, and so my routine can
 >> support a loop body with a transfer of control."
 >
-> I don't think that is any help. Such an aspect can't be statically 
-> checked, so it would just be an annoyance to most users that would 
-> have to be applied to routines before the nice syntax can be used -- 
+> I don't think that is any help. Such an aspect can't be statically
+> checked, so it would just be an annoyance to most users that would
+> have to be applied to routines before the nice syntax can be used --
 > and most would apply it even if no finalization was used.
 
 What I was suggesting is that they could use the loop-body syntax even without
@@ -1472,12 +1619,12 @@
 check for the use of "when others ... raise" and produce a warning in the
 presence of such an aspect.
 
->> More generally, if your last wishes are "critical" then finalization 
+>> More generally, if your last wishes are "critical" then finalization
 >> seems the more robust approach.
 >
-> Surely. But how many Ada programmers know that? And even if the number 
-> is 80%, the other 20% is going to write code that doesn't use 
-> finalization. And the 80% is probably going to do something else part 
+> Surely. But how many Ada programmers know that? And even if the number
+> is 80%, the other 20% is going to write code that doesn't use
+> finalization. And the 80% is probably going to do something else part
 > of the time just because it's much easier to write a handler.
 
 Using finalization for cleanup is practically a "mantra" in the C++ world, and
@@ -1488,22 +1635,22 @@
 write an aspect that says "yes I used finalization" what more can we do to
 protect the programmer against their own laziness?
 
-> I'm strongly opposed to any transfer-of-control mechanism that doesn't 
-> work for any arbitrary user code. We can't be putting unchecked 
-> restrictions on the code that can use this feature; any restrictions 
-> we want to have to be visible in the specification and checked in the 
-> body. Else we have an attractive hazard, and some percentage of Ada 
-> programmers are going to trip over it. (After all, one of the big 
-> advantages of Ada is that we don't allow arbitrary unchecked stuff to 
+> I'm strongly opposed to any transfer-of-control mechanism that doesn't
+> work for any arbitrary user code. We can't be putting unchecked
+> restrictions on the code that can use this feature; any restrictions
+> we want to have to be visible in the specification and checked in the
+> body. Else we have an attractive hazard, and some percentage of Ada
+> programmers are going to trip over it. (After all, one of the big
+> advantages of Ada is that we don't allow arbitrary unchecked stuff to
 > happen
 
 Programmers can also write "pragma Suppress(All_Checks);" because of those
-pesky constraint checks.  I really don't understand your vehemence here.  
+pesky constraint checks.  I really don't understand your vehemence here.
 Finalization is not just to protect against abort.  It is a much cleaner way
 to deal with exceptions as well.
 
-> There are several solutions that work properly without putting 
-> unchecked requirements on the potentially user-written iterator. Let's 
+> There are several solutions that work properly without putting
+> unchecked requirements on the potentially user-written iterator. Let's
 > use one of those.
 
 You will have to remind me of what you think is better than relying on
@@ -1517,36 +1664,36 @@
 Sent: Wednesday, December 21, 2016  8:27 PM
 
 ...
-> > I don't think that is any help. Such an aspect can't be statically 
-> > checked, so it would just be an annoyance to most users that would 
-> > have to be applied to routines before the nice syntax can be used -- 
+> > I don't think that is any help. Such an aspect can't be statically
+> > checked, so it would just be an annoyance to most users that would
+> > have to be applied to routines before the nice syntax can be used --
 > > and most would apply it even if no finalization was used.
-> 
-> What I was suggesting is that they could use the loop-body syntax even 
-> without this aspect, but if they wanted to permit an "exit" or other 
-> transfer of control out of the loop, they had to specify this aspect.  
-> Yes I suppose they could lie and say "I use finalization for cleanup" 
-> and then go ahead and use exception handlers.  But why would they do 
+>
+> What I was suggesting is that they could use the loop-body syntax even
+> without this aspect, but if they wanted to permit an "exit" or other
+> transfer of control out of the loop, they had to specify this aspect.
+> Yes I suppose they could lie and say "I use finalization for cleanup"
+> and then go ahead and use exception handlers.  But why would they do
 > that?
 
-So their code would compile. And they'd curse Ada for making them do it. 
+So their code would compile. And they'd curse Ada for making them do it.
 
 ...
 > And we
-> could pretty easily check for the use of "when others ... 
+> could pretty easily check for the use of "when others ...
 > raise" and produce a warning in the presence of such an aspect.
-> 
-> >> More generally, if your last wishes are "critical" then 
+>
+> >> More generally, if your last wishes are "critical" then
 > >> finalization seems the more robust approach.
 > >
-> > Surely. But how many Ada programmers know that? And even if the 
-> > number is 80%, the other 20% is going to write code that doesn't use 
-> > finalization. And the 80% is probably going to do something else 
+> > Surely. But how many Ada programmers know that? And even if the
+> > number is 80%, the other 20% is going to write code that doesn't use
+> > finalization. And the 80% is probably going to do something else
 > > part of the time just because it's much easier to write a handler.
-> 
-> Using finalization for cleanup is practically a "mantra" in the C++ 
-> world, and I don't know why you think exception handling is so much 
-> simpler.  You have to worry about multiple exceptions, and worry about 
+>
+> Using finalization for cleanup is practically a "mantra" in the C++
+> world, and I don't know why you think exception handling is so much
+> simpler.  You have to worry about multiple exceptions, and worry about
 > exception handlers that raise exceptions by mistake, etc.
 
 Really? I just use
@@ -1579,39 +1726,39 @@
 criticality, but they better not happen in "normal" usage.
 
 > Using finalization is
-> clearly a more robust way to do cleanup even without any aborts 
-> permitted.  And if we ask the user to write an aspect that says "yes I 
-> used finalization" what more can we do to protect the programmer 
+> clearly a more robust way to do cleanup even without any aborts
+> permitted.  And if we ask the user to write an aspect that says "yes I
+> used finalization" what more can we do to protect the programmer
 > against their own laziness?
 
 Don't assume anything about user code. (Or at least as little as possible.)
 
-> > I'm strongly opposed to any transfer-of-control mechanism that 
-> > doesn't work for any arbitrary user code. We can't be putting 
-> > unchecked restrictions on the code that can use this feature; any 
-> > restrictions we want to have to be visible in the specification and 
-> > checked in the body. Else we have an attractive hazard, and some 
-> > percentage of Ada programmers are going to trip over it. (After all, 
-> > one of the big advantages of Ada is that we don't allow arbitrary 
+> > I'm strongly opposed to any transfer-of-control mechanism that
+> > doesn't work for any arbitrary user code. We can't be putting
+> > unchecked restrictions on the code that can use this feature; any
+> > restrictions we want to have to be visible in the specification and
+> > checked in the body. Else we have an attractive hazard, and some
+> > percentage of Ada programmers are going to trip over it. (After all,
+> > one of the big advantages of Ada is that we don't allow arbitrary
 > > unchecked stuff to happen
-> 
-> Programmers can also write "pragma Suppress(All_Checks);" 
-> because of those pesky constraint checks.  I really don't understand 
-> your vehemence here.  Finalization is not just to protect against 
+>
+> Programmers can also write "pragma Suppress(All_Checks);"
+> because of those pesky constraint checks.  I really don't understand
+> your vehemence here.  Finalization is not just to protect against
 > abort.  It is a much cleaner way to deal with exceptions as well.
 
 Which requires writing an extra 50-100 lines of code. Too complicated for all
 but the most critical of items (and those that naturally wrap into ADTs -
 which an iterator does not).
 
-> > There are several solutions that work properly without putting 
+> > There are several solutions that work properly without putting
 > > unchecked requirements on the potentially user-written iterator.
 > > Let's use one of those.
-> 
-> You will have to remind me of what you think is better than relying on 
+>
+> You will have to remind me of what you think is better than relying on
 > finalization.
-> Exceptions that must be re-thrown and which are not handled by "when 
-> others" would seem to be at least as error prone, and require a 
+> Exceptions that must be re-thrown and which are not handled by "when
+> others" would seem to be at least as error prone, and require a
 > completely new concept in the language.
 
 There is no "throwing" of exceptions in Ada. :-) They're either raised or
@@ -1778,9 +1925,9 @@
 From: Tucker Taft
 Sent: Thursday, December 22, 2016  7:11 AM
 
-> ... P.S. I'm dubious about the alternative of using ATC, even 
-> forgetting the finalization issue. I don't think that I would expect 
-> an exit to make objects in the loop abnormal; that's always a risk 
+> ... P.S. I'm dubious about the alternative of using ATC, even
+> forgetting the finalization issue. I don't think that I would expect
+> an exit to make objects in the loop abnormal; that's always a risk
 > once abort gets involved with something.
 
 I was not suggesting that ATC per-se be used.  There is nothing asynchronous
@@ -1789,5 +1936,38 @@
 trouble with abort and ATC is not typically the unwinding mechanism, which
 could be very similar to exception propagation, but rather the fact that it
 is triggered from outside the running task.  That is not happening here.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 11, 2017  7:38 AM
+
+Here is a version [version /04 - Editor] of AI12-0189 that has a !wording
+section.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, October 11, 2017  9:26 PM
+
+By the way, I gave up on trying to use some kind of magic mechanism perhaps
+based on ATC or equivalent to get "exit" to work for the loop-body procedures.
+Instead I proposed a new aspect "Exit_Exception" which must be non-null for
+the procedure being invoked to be allowed to use exit, goto, return, or
+requeue inside the loop body.  I hope this is an acceptable approach for most
+folks.
+
+Not sure if this is relevant to the parallel loops or map/reduce construct as
+currently proposed.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, October 11, 2017  9:40 PM
+
+I think this message has the wrong subject (it should be AI12-0189-1). :-)
+
+And thanks for changing the model to something that doesn't give me indigestion
+each time I think about it.
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent