Version 1.12 of ai12s/ai12-0156-1.txt
!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 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)
Insert after the paragraph:
- The accessibility level of the anonymous access type defined by an
access_definition of an object_renaming_declaration is the same
as that of the renamed view.
the new paragraph:
- The accessibility level of the anonymous access type defined
by an access_definition of a loop_parameter_subtype_indication
is that of the loop parameter.
!corrigendum 5.5.2(2/3)
Replace the paragraph:
iterator_specification ::=
defining_identifier in [reverse] iterator_name
| defining_identifier [: subtype_indication] of [reverse] iterable_name
by:
iterator_specification ::=
defining_identifier [: loop_parameter_subtype_indication] in [reverse] iterator_name
| defining_identifier [: loop_parameter_subtype_indication] of [reverse] iterable_name
loop_parameter_subtype_indication ::= subtype_indication | access_definition
!corrigendum 5.5.2(5/4)
Replace the paragraph:
The subtype defined by the 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 subtype_indication,
if any, of a container element iterator shall statically match the default
element subtype for the type of the iterable_name.
by:
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.
!corrigendum 5.5.2(7/3)
Replace the paragraph:
An iterator_specification declares a loop parameter. 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 subtype_indication is present, it
determines the nominal subtype of the loop parameter. In an array
component iterator, if a 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
subtype_indication is not present, the nominal subtype of the loop
parameter is the default element subtype for the type of the
iterable_name.
by:
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.
!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.
****************************************************************
Questions? Ask the ACAA Technical Agent