Version 1.12 of ai12s/ai12-0156-1.txt

Unformatted version of ai12s/ai12-0156-1.txt version 1.12
Other versions for file 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 new paragraph:
!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