!standard 5.5.2(2/3) 16-04-11 AI12-0156-1/04 !standard 5.5.2(5/4) !standard 5.5.2(7/3) !standard 3.10.2(11.1/2) !class Amendment 15-02-26 !status Amendment 1-2012 16-02-29 !status WG9 Approved 16-06-13 !status ARG Approved 6-1-1 15-10-17 !status work item 15-02-26 !status received 15-02-13 !priority Medium !difficulty Easy !subject Use subtype_indication in generalized iterators !summary An anonymous access declaration can be specified in an array component iterator if necessary to match the component subtype. An optional subtype_indication can be provided with a generalized iterator. !problem One of the important features of Ada is that in almost all cases, the type of an object appears at the place where the object is declared. Thus it is not necessary to follow chains of declaration to find the type and subtype of an object. Traditional for loops are the exception to this feature, as the type of I does not appear in "for I in 1 .. 10 loop". Here, however, the type is assumed, and Ada programmers quickly get used to that. The reason for allowing the loop parameter to be specified for array component iterators and for component element iterators is to preserve this principle (at least optionally). Traditional for loops did not need such an option because the subtype is drawn directly from the given subtype_indication - the only thing that is missing is the colon. However, there are two holes in this support: (1) The syntax for array component iterators is: defining_identifier [: subtype_indication] of [reverse] iterable_name However, the syntax for the definition of the component subtype of an array type includes access_definition. Given our zeal for allowing anonymous access everywhere, it's odd that we're not allowing it here. As noted above, it's valuable that every declaration have its type easily determinable. And we already have rules to allow different anonymous access types to statically match, so there is no problem with allowing anonymous access here. (2) The name of the cursor subtype does not appear anywhere in a generalized iterator. Again, a search through a chain of declarations is needed to find the name of this subtype (it will be found as the actual subtype in the instantiation of Ada.Iterator_Interfaces, so a minimum of three searches will be needed). In order to be consistent with the other new kinds of iterators, we need to allow specifying the subtype in the case of a generalized iterator. !proposal (See Summary.) !wording Replace 5.5.2(2/3) with: (Note: square and curly brackets as in syntax, not wording modifications) iterator_specification ::= defining_identifier [: loop_parameter_subtype_definition] in [reverse] iterator_name | defining_identifier [: loop_parameter_subtype_definition] of [reverse] iterable_name loop_parameter_subtype_definition ::= subtype_indication | access_definition Modify 5.5.2(5/4): {The subtype defined by the loop_parameter_subtype_indication, if any, of a generalized iterator component iterator shall statically match the iteration cursor subtype. } The subtype defined by the {loop_parameter_}subtype_indication, if any, of an array component iterator shall statically match the component subtype of the type of the iterable_name. The subtype defined by the {loop_parameter_}subtype_indication, if any, of a container element iterator shall statically match the default element subtype for the type of the iterable_name. Modify 5.5.2(7/3) by swapping the second and third sentences and making the other changes indicated: An iterator_specification declares a loop parameter. In {a generalized iterator, }an array component iterator{,} or a container element iterator, if a {loop_parameter_}subtype_indication is present, it determines the nominal subtype of the loop parameter. In a generalized iterator, {if a loop_parameter_subtype_indication is not present, }the nominal subtype of the loop parameter is the iteration cursor subtype. In an array component iterator, if a {loop_parameter_}subtype_indication is not present, the nominal subtype of the loop parameter is the component subtype of the type of the iterable_name. In a container element iterator, if a {loop_parameter_}subtype_indication is not present, the nominal subtype of the loop parameter is the default element subtype for the type of the iterable_name. Replace AARM 5.5.2(8.a/4) with: The loop parameter of a generalized iterator has the same accessibility as the loop statement. This means that the loop parameter object is finalized when the loop statement is left. (It also may be finalized as part of assigning a new value to the loop parameter.) For array component iterators, the loop parameter directly denotes an element of the array and has the accessibility of the associated array. For container element iterators, the loop parameter denotes the result of the indexing function call (in the case of a constant indexing) or a generalized reference thereof (in the case of a variable indexing). Roughly speaking, the loop parameter has the accessibility level of a single iteration of the loop. More precisely, the function result (or the generalized reference thereof) is considered to be renamed in the declarative part of a notional block statement which immediately encloses the loop's sequence_of_statements; the accessibility of the loop parameter is that of the block statement. And add after 3.10.2(11.1/2) as another bulleted list item The accessibility level of an anonymous access type defined by an access_definition of a loop_parameter_subtype_indication is that of the loop parameter. !discussion For hole 1, we allow anonymous access types for consistency with other kinds of object declaration (including extended return statements and generic formal parameters), and with the syntax for component declarations. Whether we should have done that for object declarations and component declarations can be argued, but since we have, there should not be places where anonymous access types cannot be written. Notice that static matching will always fail if an access_definition is used for container element iterators, as the Iterator_Element has to be a "name", and that does not include anonymous access types. We've revised the accessibility rules to cover these anonymous access types. We also revised the note describing the accessibility of loop parameters to properly explain the container element iterator case, as the old description seemed to require the nonsense of keeping the results of the indexing function calls until the loop exited (as opposed to just the end of the iteration). For hole 2, we allow an optional subtype_indication on a generalized iterator. We don't want to force readers to look through many declarations to find out the type of a loop parameter. We allow that type to be optional, however, as it often is obvious from context. For instance, if one is iterating a language-defined container, everyone should know that the cursor type is named Cursor and it's defined in the instance that defines the container type. But that's not true for user-defined iterators, which may have been added to existing types for which the name "Cursor" is not appropriate. We don't need to allow an access_definition in a generalized iterator, as the actual type provided to any generic instance (including an instance of Ada.Iterator_Interfaces) is a subtype_mark; it cannot be an anonymous access_definition. We use loop_parameter_subtype_definition anyway, just to simplify the wording. We could have allowed an optional subtype_indication in a traditional for loop as well. But "in" here acts much like ":", so we don't really need the extra subtype. And the static matching requirement would mean that the same subtype would have to be written twice in most circumstances: for I : Short in Short loop A charter member of the department of redundancy department. In addition, it would have required additional wording and syntax changes in subclause 5.5. So this does not seem worthwhile. !corrigendum 3.10.2(11.1/2) @dinsa @xbullet of an @fa is the same as that of the renamed view.> @dinst @xbullet of a @fa is that of the loop parameter.> !corrigendum 5.5.2(2/3) @drepl @xcode<@fa@fa< ::= > @fa @ft<@b> [@ft<@b>] @ft<@i>@fa | @fa @ft<@b> [@ft<@b>] @ft<@i>@fa> @dby @xcode<@fa@fa< ::= > @fa @ft<@b> [@ft<@b>] @ft<@i>@fa | @fa @ft<@b> [@ft<@b>] @ft<@i>@fa @fa> !corrigendum 5.5.2(5/4) @drepl The subtype defined by the @fa, if any, of an array component iterator shall statically match the component subtype of the type of the @i@fa. The subtype defined by the @fa, if any, of a container element iterator shall statically match the default element subtype for the type of the @i@fa. @dby The subtype defined by the @fa, if any, of a generalized iterator component iterator shall statically match the iteration cursor subtype. The subtype defined by the @fa, if any, of an array component iterator shall statically match the component subtype of the type of the @i@fa. The subtype defined by the @fa, if any, of a container element iterator shall statically match the default element subtype for the type of the @i@fa. !corrigendum 5.5.2(7/3) @drepl An @fa declares a @i. In a generalized iterator, the nominal subtype of the loop parameter is the iteration cursor subtype. In an array component iterator or a container element iterator, if a @fa is present, it determines the nominal subtype of the loop parameter. In an array component iterator, if a @fa is not present, the nominal subtype of the loop parameter is the component subtype of the type of the @i@fa. In a container element iterator, if a @fa is not present, the nominal subtype of the loop parameter is the default element subtype for the type of the @i@fa. @dby An @fa declares a @i. In a generalized iterator, an array component iterator, or a container element iterator, if a @fa is present, it determines the nominal subtype of the loop parameter. In a generalized iterator, if a @fa is not present, the nominal subtype of the loop parameter is the iteration cursor subtype. In an array component iterator, if a @fa is not present, the nominal subtype of the loop parameter is the component subtype of the type of the @i@fa. In a container element iterator, if a @fa is not present, the nominal subtype of the loop parameter is the default element subtype for the type of the @i@fa. !ASIS No ASIS effect. !ACATS test An ACATS C-Test is needed to check that the new capabilities are supported. !appendix This AI was split from AI12-0151-1 by the February 26th, 2015 ARG phone meeting. To find the initial e-mail discussion, check that AI. **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 1:22 AM My Madrid homework includes taking a look at AI12-0156 (Use subtype_indication in generalized iterators). 1) Did the group really agree (intent only) that we want to change the syntax for 5.5.2(3) so that [: subtype_indication] is replaced with [: [subtype_indication | access_definition]] in order to allow something like type Vec is array (1..10) of access Integer; X : Vec; begin for Ref : access Integer of X loop Ref.all := Ref.all + 1; end loop; end; ? That seems like more trouble than it is worth, especially in the access to subprogram case; consider named notation calls. type Vec2 is array (1..10) of access procedure (Aaa, Bbb : Integer); X2 : Vec2; begin for Ref2 : access procedure (Bbb, Aaa : Integer) of X2 loop Ref2.all (Aaa => 123, Bbb => 456); -- meaning? end loop; end; These new types/subtypes were supposed to completely redundant. I think the simplest solution would be to leave the syntax as it is. If you have an array whose element type is anonymous, then you just can't use the new syntax to redundantly (re-)specify the type/subtype and that's just tough. What do others think? 2) 5.5.2(8.a/4) states (as a ramification): The loop parameter of a generalized iterator has the same accessibility as the loop statement. This means that the loop parameter object is finalized when the loop statement is left. (It also may be finalized as part of assigning a new value to the loop parameter.) For array component iterators and container element iterators, the loop parameter directly denotes an element of the array or container and has the accessibility of the associated array or container. AFAIK, this is fine for generalized iterators and for array component iterators (although if we make the syntax change discussed in question #1 above, then we'd probably have to update 3.10.2(11.1/2) to treat the new kind of anonymous access type like an anonymous access type occurring in a rename declaration which renames a component of the array). For container element iterators, this rule about the accessibility of a loop parameter seems wrong. Even in the case where the loop parameter is a variable (as opposed to a constant) there is no reason to assume that the loop parameter "directly denotes an element of the ... container" and therefore has the same accessibility level as the container. This is even more obvious in the constant case. For example, suppose you have a map container and you provide a variable indexing function which takes an aliased in out parameter as well as a key; if the key is special in some way, then the function ignores the corresponding map element and instead returns a reference-type result which designates the parameter. If the container is declared in a more global scope than the actual parameter of the call, this could lead to a dangling reference. 5.5.2(13/3) states Otherwise, the sequence_of_statements is executed with the loop parameter denoting an indexing (see 4.1.6) into the iterable container object for the loop. An indexing is defined to be equivalent to a function call. So what is the accessibility level of this function call and, equivalently, when is the function result object finalized? It seems clear that we want the loop parameter for single loop iteration to be finalized at the end of that loop iteration. We don't want calls from multiple iterations to accumulate, unfinalized until the entire loop statement completes. That would require significant implementation effort in order to accomplish something that nobody wants. That's also, I believe, what a strict reading of the current wording of the RM requires. Unfortunately, a single iteration of a loop isn't a master at all, so it certainly can't be the master of the function call. I think we need to clarify the equivalence for a container element iterator loop to include a block statement which encloses the loop body; the loop parameter is declared by an appropriate renaming declaration which occurs in the (otherwise empty) declarative part of the block statement. The block statement then acts as the desired master. This seems simpler than adding a new kind of master to the list given in 7.6.1(3/2). Does this seem like the right approach for defining the accessibility level of the loop parameter of a container element iterator loop? Does this question belong in AI12-0156, in a separate AI, or in the Steve-was-just-confused-again file? **************************************************************** From: Randy Brukardt Sent: Tuesday, October 6, 2015 11:56 AM ... > 1) Did the group really agree (intent only) that we want to change > the syntax for 5.5.2(3) so that > [: subtype_indication] > is replaced with > [: [subtype_indication | access_definition]] We discussed it, and you indicated possible issues with accessibility, so we sent you off to study it. We certainly didn't make a decision either way; as it's much harder to put something in where there is no wording than to take out something we decide not to do, it needs to be written up as if it is in. That's how we can judge if the complexity is excessive. ... > That seems like more trouble than it is worth, especially > in the access to subprogram case; consider named notation calls. > > type Vec2 is array (1..10) of > access procedure (Aaa, Bbb : Integer); > X2 : Vec2; > begin > for Ref2 : access procedure (Bbb, Aaa : Integer) of X2 loop > Ref2.all (Aaa => 123, Bbb => 456); -- meaning? Doesn't this already happen for renames? What does it do to prevent this problem (or did you just discover another bug)??? I.e. Ref2 : access procedure (Bbb, Aaa : Integer) of X2 renames X2(1); Ref2.all (Aaa => 123, Bbb => 456); -- meaning? In any case, I don't see anything new here. > 2) 5.5.2(8.a/4) states (as a ramification): ... > For container element iterators, this rule about the > accessibility of a loop parameter seems wrong. > > Even in the case where the loop parameter is a variable (as opposed > to a constant) there is no reason to assume that the loop parameter > "directly denotes an element of the ... container" and therefore > has the same accessibility level as the container. This is even > more obvious in the constant case. Correct. ... > An indexing is defined to be equivalent to a function call. Right. A container element iterator parameter is a renaming of the result of that function call. (That's the only model that makes sense.) > So what is the accessibility level of this function call and, > equivalently, when is the function result object finalized? > It seems clear that we want the loop parameter for single loop > iteration to be finalized at the end of that loop iteration. > We don't want calls from multiple iterations to accumulate, > unfinalized until the entire loop statement completes. > That would require significant implementation > effort in order to accomplish something that nobody wants. > That's also, I believe, what a strict reading of the current > wording of the RM requires. > > Unfortunately, a single iteration of a loop isn't a master at all, > so it certainly can't be the master of the function call. > > I think we need to clarify the equivalence for a container > element iterator loop to include a block statement which encloses > the loop body; the loop parameter is declared by an appropriate > renaming declaration which occurs in the (otherwise empty) > declarative part of the block statement. The block statement > then acts as the desired master. > > This seems simpler than adding a new kind of master to the list > given in 7.6.1(3/2). I don't think it's "simpler", given there the "equivalence" is given in English and is *very* vague. Indeed, I'm not sure there is any reason to even state this normatively -- what else could it be? The only alternative is that the loop keeps every indexing to the end of the loop body, and that violates the Dewar rule. So I think that the "solution" is just to enhance the AARM note, and leave the normative wording alone. Otherwise, I think you need to update the normative wording for all three cases (I don't see why one of them should be more special than the others, and it's already non-obvious that the other cases are not per-iteration.) We resisted that because no one really wants to hair up the description just for an accessibility rule that no one will ever care about. > Does this question belong in AI12-0156, in a separate AI, or in the > Steve-was-just-confused-again file? Well, I think most of us would like to put all accessibility-related questions into AI12-9999999999999-1 that will never actually appear on the agenda. :-) But given that it's related to the anonymous access part of the proposal (even if that gets dropped), I'd just stick it into AI12-0156-1. **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 12:08 PM > Doesn't this already happen for renames? > i.e. > > Ref2 : access procedure (Bbb, Aaa : Integer) of X2 renames > X2(1); > > Ref2.all (Aaa => 123, Bbb => 456); -- meaning? I was wondering about that very point earlier today. What is the correct output for this example? with Text_IO; procedure Aatsor is -- anonymous access to subprogram object renaming procedure Foo (X, Y : Integer) is use Text_IO; begin Put_Line ("X =" & Integer'Image (X)); Put_Line ("Y =" & Integer'Image (Y)); end; Ref : access procedure (Aaa, Bbb : Integer := 111); Renamed_Ref : access procedure (Bbb, Aaa : Integer := 222) renames Ref; begin Ref := Foo'Access; Renamed_Ref.all (Aaa => 333); end; [Editor's note: The remainder of the thread on this topic is in the Appendix of AI12-0066-1.] **************************************************************** From: Steve Baird Sent: Tuesday, October 6, 2015 5:03 PM > .., it needs to be written up as if it is in. > That's how we can judge if the complexity is excessive. I think the new wording would consist of a) The syntax change b) The accessibility level definition rule mentioned earlier (treat it like an anonymous access type of an object renaming). b) Yet another copy of the name resolution rules given in 8.5.1(3/2) and 12.4(5/2). Perhaps introduce some new term to reduce the duplication. I think the complexity is excessive for the small benefit of allowing the ": access procedure" in for X : access procedure of My_Array_With_An_Anonymous_Element_Type loop but that's just my opinion. > But at this point, I don't think it's worth fixing. Hard to argue with that. I got to looking at this issue because I was asked to look at anonymous access types in array component iterator loops and it seemed that those are similar to anonymous access types in object renamings. As noted above, I'm in favor of not making any changes to allow the array loop case. If we do that, then it would be fine with me to just let sleeping dogs lie. ****************************************************************