Version 1.4 of ai12s/ai12-0047-1.txt

Unformatted version of ai12s/ai12-0047-1.txt version 1.4
Other versions for file ai12s/ai12-0047-1.txt

!standard 5.5.2(6/3)          13-01-28 AI12-0047-1/04
!class binding interpretation 12-12-01
!status Amendment 202x 12-12-31
!status work item 13-01-07
!status ARG Approved 11-0-0 12-12-08
!status work item 12-12-01
!status received 12-11-12
!priority Medium
!difficulty Medium
!subject Generalized iterators and finalization of the associated object
!summary
The iterable_name or iterator_name of a iterator cannot be a discriminant-dependent subcomponent of a mutable type.
The iterable_name or iterator_name of a iterator is not finalized until the loop completes.
!question
1) Consider:
subtype Index is Integer range 0 .. 100;
type Rec (Last : Index := 50) is record F : String (1 .. Last); end record;
X : Rec;
begin for Char of X.F loop X := (0, ""); Char := '?'; end loop;
In this case, the assignment to X makes the array object disappear. This should be illegal, right? (Yes.)
2) The following is defined to be a master (7.6.1(3/2)):
... the evaluation of an expression, function_call, or range that is not part of an enclosing expression, function_call, range, or simple_statement other than a simple_return_statement
Consider:
for I of Func_Returning_Array_With_Controlled_Elements loop
The rule above means that the function call result object gets finalized before beginning the first iteration of the loop. This is not good (especially as the tampering mechanism assumes that this finalization happens when the loop is exited).
Should something be changed? (No.)
!recommendation
(See summary.)
!wording
Add after 5.5.2(6/3):
The iterator_name or iterable_name of an iterator_specification shall not denote a subcomponent that depends on discriminants of an object whose nominal subtype is unconstrained, unless the object is known to be constrained.
!discussion
Problem #1 is solved by following the lead of renaming. We directly repeat the interesting rule as defining iterators in terms of renaming would drag in other rules that may or may not be appropriate. In particular, it would require that the object can be clobbered inside the loop (with unpredictable results for a container iterator):
for E of X loop ... X := <something>; ... end loop;
Ada.Containers has tampering checks to prevent this situation (the assignment would raise Program_Error), but user-defined packages may not. So we do not take this approach.
Problem #2 is not a problem at all, as the master of a return object of a function call is that which encloses the function call; whether the function call is a master has no impact on that. (See AARM 7.6.1(3.c/2).) The fact that the function call is a master mainly is important to specify the lifetime of the actual parameters to be short, as in the following example:
for I of Func_Returning_Array (Func_Returning_Record_With_Controlled_Components) loop
In this case, the result of Func_Returning_Record_With_Controlled_Components is finalized before the loop begins to execute (assuming the parameter to Func_Returning_Array is not aliased), as the call of Func_Returning_Array is its master, while the result of Func_Returning_Array is not finalized until the loop is complete (as the loop statement is the master). This is what we want for generalized iterators, so no change is needed.
!corrigendum 5.5.2(6/3)
Insert after the paragraph:
In a container element iterator whose iterable_name has type T, if the iterable_name denotes a constant or the Variable_Indexing aspect is not specified for T, then the Constant_Indexing aspect shall be specified for T.
the new paragraph:
The iterator_name or iterable_name of an iterator_specification shall not denote a subcomponent that depends on discriminants of an object whose nominal subtype is unconstrained, unless the object is known to be constrained.
!ACATS test
ACATS B-Tests should be created to test these rules.
!appendix

From: Steve Baird
Sent: Monday, November 12, 2012 12:35 PM

Two issues with generalized iterators.

1) We need to deal with the following example, either by making it illegal
   (following the example of 8.5.1(5/3)) or by defining its execution to be
   erroneous (following the example of 6.4.1(18/3)):

    subtype Index is Integer range 0 .. 100;

    type Rec (Last : Index := 50) is
       record F : String (1 .. Last); end record;

    X : Rec;
   begin
    for Char of X.F loop
       X := (0, "");
       Char := '?';
    end loop;

I think we want tn array component iterator to behave (statically and
dynamically - see next item) as though a rename of the array object were
introduced. If such a rename would be illegal, then the iterator should also be
illegal. We don't want new constructs to introduce new forms of erroneous
behavior (and hence new ways of writing unreliable software) if we can avoid it.

I haven't thought about whether analogous problems exist for the other
generalized loop iteration forms.

Opinions?

2) The following is defined to be a master (7.6.1(3/2)):

    ... the evaluation of an expression, function_call, or range that is
    not part of an enclosing expression, function_call, range, or
    simple_statement other than a simple_return_statement

This is generally a good thing. In a case like

    if Function_With_Controlled_Components.Flag then
      P;
    else
      Q;

, it means that the function call object is finalized before P or Q is called.

This is good.

In the example

      for I in 1 .. Function_Call.Scalar_Field loop

we will finalize the function result object before beginning the first iteration
of the loop (but after storing away the pre-finalization value of the
Scalar_Field component).

Again, this is good.

However, generationed loop iteration introduces (for the first time, I think)
the possibility that a non-scalar expression can be a master.

Consider:

    For I of Func_Returning_Array_With_Controlled_Elements loop

As the rules stand today, I believe the function call result object gets
finalized before beginning the first iteration of the loop (just like the
previous example).

This is not good.

I think this could be solved by adding the word "elementary"
(or perhaps "scalar"?) to the 7.6.1 wording cited above, so that it reads

   .... the evaluation of an elementary expression, function_call,
  or range that is not part of an enclosing ...

With that rule, the nearest enclosing master for the function call would be the
loop statement itself, so the function result object would be finalized after
the loop is completed (which is what we want).

Opinions?

****************************************************************

From: Tucker Taft
Sent: Monday, November 12, 2012  1:21 PM

> 1) ... I think we want the array
> component iterator to behave (statically and dynamically - see next
> item) as though a rename of the array object were introduced.
> If such a rename would be illegal, then the iterator should also be
> illegal. We don't want new constructs to introduce new forms of
> erroneous behavior (and hence new ways of writing unreliable
> software) if we can avoid it.
>
> I haven't thought about whether analogous problems exist for the other
> generalized loop iteration forms.
>
> Opinions?

Agreed.

> 2) The following is defined to be a master (7.6.1(3/2)):
>
>     ... the evaluation of an expression, function_call, or range that is
>     not part of an enclosing expression, function_call, range, or
>     simple_statement other than a simple_return_statement
>
> This is generally a good thing. In a case like
>
>     if Function_With_Controlled_Components.Flag then
>       P;
>     else
>       Q;
>
> , it means that the function call object is finalized before P or Q is
> called.
>
> This is good.
>
> In the example
>
>       for I in 1 .. Function_Call.Scalar_Field loop
>
> we will finalize the function result object before beginning the first
> iteration of the loop (but after storing away the pre-finalization
> value of the Scalar_Field component).
>
> Again, this is good.
>
> However, generationed loop iteration introduces (for the first time, I
> think) the possibility that a non-scalar expression can be a master.
>
> Consider:
>
>     For I of Func_Returning_Array_With_Controlled_Elements loop
>
> As the rules stand today, I believe the function call result object
> gets finalized before beginning the first iteration of the loop (just
> like the previous example).
>
> This is not good.
>
> I think this could be solved by adding the word "elementary"
> (or perhaps "scalar"?) to the 7.6.1 wording cited above, so that it
> reads
>
>    .... the evaluation of an elementary expression, function_call,
>   or range that is not part of an enclosing ...
>
> With that rule, the nearest enclosing master for the function call
> would be the loop statement itself, so the function result object
> would be finalized after the loop is completed (which is what we
> want).
>
> Opinions?

This makes me somewhat nervous, as it seems like a big change.
But perhaps it is OK.  There are very few places where non-elementary
expressions occur where they are not part of a larger expression, and those may
mostly be cases where some kind of implicit rename is taking place.

The other solution would be to treat these generalized iterators as implicit
renames, since you have already suggested that in part (1).

****************************************************************

From: Steve Baird
Sent: Monday, November 12, 2012 12:35 PM

> The other solution would be to treat these generalized iterators as
> implicit renames, since you have already suggested that in part (1).

Just fleshing out your suggestion, this approach would also include implicitly defining an enclosing block statement, right?
The implicit rename declaration has to live somewhere.

...
> I haven't thought about whether analogous problems exist for the other
> generalized loop iteration forms.

I think we may need to look more closely at this question before deciding
between the two approaches (i.e., change the definition of master vs. implicit
renames in implicit blocks).

Incidentally, typos in previous message:
    "generationed loop iteration" => "generalized loop iteration"
     "we want tn array" => "we want an array"

****************************************************************

From: Randy Brukardt
Sent: Monday, November 12, 2012  6:06 PM

Implicit renames might cause issues with user-defined iterators. In particular,
your example of:

    for E of X loop
       ...
       X := <something>;
       ...
    end loop;

looks like it could be trouble if X is considered a rename. The iteration could
end up screwed up. The language-defined containers "solve" this problem with the
tampering mechanism, and I think the only problem for arrays would be the
example you originally showed (which would be illegal if a rename), so it mostly
would be a problem with user-defined iterators.

OTOH, if you fixed the problem with masters and implicit temporaries, then the
problem (1) would not need to be illegal (Constraint_Error might be raised,
though, not sure which is worse).

****************************************************************

From: Randy Brukardt
Sent: Monday, November 12, 2012  6:53 PM

> I haven't thought about whether analogous problems exist for the other
> generalized loop iteration forms.

Don't they have to? Just wrap the container or iterator object in a variant
record, and change the discriminant of the variant within the loop to make the
object disappear. Of course this is a pathology (especially for the iterator
object case, it's hard to imagine any good reason to put those into a record),
but it seems dangerous enough to detect (the only alternative being erroneous
execution, which we want to avoid if possible).

We can fix this problem easily by adapting 8.5.1(5/3) directly:

The iterator_name or iterable_name of a iterator_specification shall not be a
subcomponent that depends on discriminants of an object a variable whose nominal
subtype is unconstrained, unless the object is known to be constrained.

This is simpler than trying to drag in the entire mechanism of renaming
(presuming we don't need it anyway for the master problem).

I'm not going to waste time now considering the master issue...(no sensible
solution jumps out at me).

****************************************************************

From: Randy Brukardt
Sent: Monday, December 31, 2012  10:26 PM

AI12-0047-1 changes the definition of masters to ensure that the object in an
iterator like:

       for E of Func loop
          ...
       end loop;

is not finalized before the end of the loop.

However, I think we missed something in that wording. The problem is that
compound statements are not masters, so the completion of the loop does not
finalize anything. That means that Func in the above could live too long (until
whatever master encloses the loop is finalized).

That's a problem as it would mean that the natural implementation of the
tampering checks for the containers would leave the containers locks for some
arbitrary amount of time after the loop completed. That's surely not the intent,
nor is it a good idea.

I think that we have to add loop_statement with an iterator_specification to the
list of things that can be masters.

Thoughts??

P.S. I'm unconvinced that we needed to make the change to "scalar
function_calls" in 7.6.1(3/2) that we approved, because that does not apply to
the result of the function_call (it is whatever encloses a function call that
determines when the function result is finalized, not the master that is the
function call. This latter master matters for the parameters of the call, not
the result, as is explained in the AARM notes following 7.6.1(3/2). This change
is harmless, however, so I'm not going to worry about it further.

P.P.S. The 2nd question in the AI is completely bogus because of the
misinterpretation noted in the P.S. Should it get rewritten to explain the
*real* problem??

****************************************************************

From: Steve Baird
Sent: Monday, January 7, 2013  2:25 PM

> However, I think we missed something in that wording. The problem is
> that compound statements are not masters, so the completion of the
> loop does not finalize anything.

A compound statement is a master and this "problem" therefore isn't a problem.

7.6.1(3/2):
    Leaving an execution happens immediately after its completion,
    except in the case of a master: ...; the execution of a statement;
    or ....

****************************************************************

From: Tucker Taft
Sent: Monday, January 7, 2013  3:28 PM

> However, I think we missed something in that wording. The problem is
> that compound statements are not masters, so the completion of the
> loop does not finalize anything. That means that Func in the above
> could live too long (until whatever master encloses the loop is finalized).

As Steve pointed out, all statements are masters.

> ...
> P.S. I'm unconvinced that we needed to make the change to "scalar
> function_calls" in 7.6.1(3/2) that we approved, because that does not
> apply to the result of the function_call (it is whatever encloses a
> function call that determines when the function result is finalized,
> not the master that is the function call. This latter master matters
> for the parameters of the call, not the result, as is explained in the
> AARM notes following 7.6.1(3/2). This change is harmless, however, so
> I'm not going to worry about it further.

I agree.  The 2nd question of the AI is a red herring.  We all got suckered in
by Steve's logic! ;-)  There was never any problem, and our fix, though benign,
was unnecessary.

> P.P.S. The 2nd question in the AI is completely bogus because of the
> misinterpretation noted in the P.S. Should it get rewritten to explain
> the
> *real* problem??

Yes, probably.  It is unwise to leave this AI in a state where it is clearly
misleading.

****************************************************************

From: Steve Baird
Sent: Monday, January 7, 2013  6:12 PM

>> P.S. I'm unconvinced that we needed to make the change to "scalar
>> function_calls" in 7.6.1(3/2) that we approved, because that does not
>> apply to the result of the function_call (it is whatever encloses a
>> function call that determines when the function result is finalized,
>> not the master that is the function call. This latter master matters
>> for the parameters of the call, not the result, as is explained in the
>> AARM notes following 7.6.1(3/2). This change is harmless, however, so
>> I'm not going to worry about it further.

> I agree.  The 2nd question of the AI is a red herring.  We all got
> suckered in by Steve's logic! ;-)  There was never any problem, and
> our fix, though benign, was unnecessary.

The AARM wording we are talking about here is:
   The fact that a function_call is a master does not change the
   accessibility of the return object denoted by the function_call;
   that depends on the use of the function_call.

I agree that I overlooked this.

Now you two have me worrying that the fix I thought was necessary is not benign.

If we have

      for I of Container_Valued_Function
                 (Function_With_Controlled_Result) loop
         ...;
      end loop;

then does the change we approved change the point at which we finalize the
function result object for the call to Function_With_Controlled_Result?

Without the change, the enclosing call is a master and so the controlled
function result object is finalized before the first iteration of the loop body.
With the change, that enclosing call is no longer a master. Doesn't that mean
that the controlled function result object is therefore not finalized until the
completion of the loop statement?

That seems like an undesirable change. The main point here is that we want to
avoid requiring implementations to do anything different than whatever they were
doing before.

Bob Duff wrote (on another thread):
> I think this discussion illustrates the point that when we meddle with
> RM wording, we're about as likely to break things as to fix things

Bob, I have no idea what you might be referring to.

****************************************************************

From: Tucker Taft
Sent: Monday, January 7, 2013  7:33 PM

> Now you two have me worrying that the fix I thought was necessary is
> not benign. ...

Sounds like we should undo this change.

****************************************************************

From: Randy Brukardt
Sent: Monday, January 7, 2013  7:42 PM

Agreed. It's unnecessary, and might change run-time behavior. No reason for
that.

****************************************************************

Questions? Ask the ACAA Technical Agent