Version 1.2 of ai05s/ai05-0219-1.txt

Unformatted version of ai05s/ai05-0219-1.txt version 1.2
Other versions for file ai05s/ai05-0219-1.txt

!standard 10.2.1(18/2)          10-08-12 AI05-0219-1/02
!class binding interpretation 10-06-13
!status Amendment 2012 10-08-12
!status ARG Approved 8-0-1 10-06-19
!status work item 10-06-13
!status received 10-05-06
!priority Low
!difficulty Easy
!qualifier Clarification
!subject Pure permissions and limited parameters
!summary
The permission to eliminate calls on pure subprograms cannot be used if any parameter has a part whose full type is immutably limited.
!question
10.2.1(18/2) is a dynamic semantics rule, but it talks about "parameters of a limited type". "Limited" is a static category that depends on visibility; wouldn't "immutably limited" be better? (No, but clarification is needed.)
!recommendation
(See Summary.)
!wording
Modify 10.2.1(18/2):
If a library unit is declared pure, then the implementation is permitted to omit a call on a library-level subprogram of the library unit if the results are not needed after the call. In addition, the implementation may omit a call on such a subprogram and simply reuse the results produced by an earlier call on the same subprogram, provided that none of the parameters nor any object accessible via access values from the parameters [are of a limited type]{have any part that is of a type whose full type is an immutably limited type}, and the addresses and values of all by-reference actual parameters, the values of all by-copy-in actual parameters, and the values of all objects accessible via access values from the parameters, are the same as they were at the earlier call. This permission applies even if the subprogram produces other side effects when called.
!discussion
"Immutably limited" isn't strong enough, as it doesn't include all types with limited parts. However, "limited type" here is vague, we are really talking about types whose full type is limited.
To be consistent, we use the same wording as for build-in-place: "full type of any part of the object is immutably limited".
!corrigendum 10.2.1(18/2)
Replace the paragraph:
If a library unit is declared pure, then the implementation is permitted to omit a call on a library-level subprogram of the library unit if the results are not needed after the call. In addition, the implementation may omit a call on such a subprogram and simply reuse the results produced by an earlier call on the same subprogram, provided that none of the parameters nor any object accessible via access values from the parameters are of a limited type, and the addresses and values of all by-reference actual parameters, the values of all by-copy-in actual parameters, and the values of all objects accessible via access values from the parameters, are the same as they were at the earlier call. This permission applies even if the subprogram produces other side effects when called.
by:
If a library unit is declared pure, then the implementation is permitted to omit a call on a library-level subprogram of the library unit if the results are not needed after the call. In addition, the implementation may omit a call on such a subprogram and simply reuse the results produced by an earlier call on the same subprogram, provided that none of the parameters nor any object accessible via access values from the parameters have any part that is of a type whose full type is an immutably limited type, and the addresses and values of all by-reference actual parameters, the values of all by-copy-in actual parameters, and the values of all objects accessible via access values from the parameters, are the same as they were at the earlier call. This permission applies even if the subprogram produces other side effects when called.
!ACATS Test
This is just a permission, it is hard to test usefully. (We could try to test that it is not applied in these cases, but of course it might not be used even if the rule here is incorrectly implemented.)
!appendix

From: Bob Duff
Sent: Thursday, May 6, 2010  8:35 AM

In 10.2.1 Elaboration Control, we have:

                         Implementation Permissions

18/2  {AI95-00366-01} If a library unit is declared pure, then the
implementation is permitted to omit a call on a library-level subprogram of the
library unit if the results are not needed after the call. In addition, the
implementation may omit a call on such a subprogram and simply reuse the results
produced by an earlier call on the same subprogram, provided that none of the
parameters nor any object accessible via access values from the parameters are
of a limited type, and the addresses and values of all by-reference actual
parameters, the values of all by-copy-in actual parameters, and the values of
all objects accessible via access values from the parameters, are the same as
they were at the earlier call. [This permission applies even if the subprogram
produces other side effects when called.]

Why does it say "limited", given that this is a run-time issue -- shouldn't it
say "immutably limited"?

P.S. Why does this limitedness exception exist in the first place?

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

From: Bob Duff
Sent: Thursday, May 6, 2010  8:57 AM

> Why does it say "limited", given that this is a run-time issue --
> shouldn't it say "immutably limited"?

Also, there are three occurrences of "parameter" in this para that are not
qualified by either "formal" or "actual".  Seems like plain "parameter" is an
ambiguous term, and should be "formal" or "actual" (or if you like verbosity,
"formal parameter" or "actual parameter").

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  9:16 AM

I don't think "immutably" is quite right.
What matters is whether the type is limited "deep down."  Immutably is more
stringent than that, since it is a visible indication that the type is going to
"stay" limited, whereas a simple "limited private" type is not considered
immutably limited even if the full type is a task type.  I agree this is dynamic
semantics, and when we say things like "limited" we mean "really limited."
"Immutably limited" is more of a static semantics-level term.

I'm also not sure why formal vs. actual matters, since again we are talking
dynamic semantics, and at the point of call they have the same value,
presumably.

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  9:21 AM

To me it is really ugly to have a situation where in one case we have a call
eliminated, and in another case we don't JUST because of the current visibility,
so indeed we don't want to imply that the check is at the point of call.

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  9:41 AM

I *think* we are agreeing that this permission has nothing to do with
visibility, and hence "immutably limited" is not the appropriate term, since
that is related to visibility.

Similarly, actual vs. formal doesn't matter, since we are talking about the
run-time value (and address if by-reference), not static semantic properties
which might distinguish actual from formal.

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  9:51 AM

>>> I don't think "immutably" is quite right.
>>> What matters is whether the type is limited "deep down."  Immutably
>>> is more stringent than that, since it is a visible indication that
>>> the type is going to "stay" limited, whereas a simple "limited
>>> private" type is not considered immutably limited even if the full
>>> type is a task type.  I agree this is dynamic semantics, and when we
>>> say things like "limited" we mean "really limited."  "Immutably
>>> limited" is more of a static semantics-level term.

Immutably limited is stronger than what you have in mind right? But perhaps it
is the simplest rule to follow here? no?

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  9:26 AM

The exception for limited types is because there is a presumption that their
"state" is not fully captured by their "value" (whatever "value" means).
Certainly trying to decide whether a task object has the same "value" as at an
earlier call would be difficult.

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  9:32 AM

> The exception for limited types is because there is a presumption that
> their "state" is not fully captured by their "value" (whatever "value"
> means).
> Certainly trying to decide whether a task object has the same "value"
> as at an earlier call would be difficult.

I would say that since you can't prove it has the same value, you just don't
eliminate the call in that case, in other words I would replace this with a note
if it is to be mentioned at all that said

Note: since there is a presumption that the state of an immutably limited object
may not be fully captured by their value, generally calls that involve such a
value will not be eliminated, since it would be impossible for the compiler to
know whether the values were the same in two calls.

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  9:48 AM

I don't believe the term "value" is even well defined for (deep-down) limited
types. That is the fundamental reason for the exception.  Your suggested wording
and the use of the term "generally" implies that if the compiler were smart
enough it could determine whether the value was the same, but I think that is
mistaken for a limited type.  Even if the bits are identical, and nothing was
done to the object between the two calls, you still can't legitimately consider
it to have the same value if it is limited.

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  9:57 AM

OK, but lets try to find a simple way of describing this, I hate to have yet a
third notion of limitedness :-(

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  9:59 AM

A suggestion Ed made in our internal discussion, is that the exception should
depend on the limitedness of the type (not immutable limitedness) at the point
of the subprogram declaration, on the grounds that the client should know if the
exception applies.

Interestingly this would have (accidentally) helped out our customer, who had
pure routines that did I/O and was upset that calls got eliminated (!)

But the calls in question had a limited parameter (by accident I think), but the
full declaration was non-limited.

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

From: Bob Duff
Sent: Thursday, May 6, 2010  10:06 AM

> I don't think "immutably" is quite right.
> What matters is whether the type is limited "deep down."

We used to use the term "inherently limited" during the Ada 9X project, but we
didn't put it in the RM.  I think it means the same as "deep down limited". Also
synonymous with "limited and never becomes nonlimited".

I thought "immutably limited" was a synonym for what we used to call "inherently
limited".  This was added to the RM post-2005.  Am I wrong?  How do these two
terms differ?

GNAT has a function Is_Inherently_Limited(Node_Id)-->Boolean,
which I named before the term "immutably limited" was invented.  Today I
suggested it should be changed to Is_Immutably_Limited, but now I think you're
telling me that's wrong.  (Is_Inherently_Limited was called
Is_Return_By_Reference previously; I changed it because that's an Ada 95 term.)

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  10:32 AM

If you look up immutably limited, it
is strictly a static semantics property.
It doesn't include record types that are limited only because they include a
task, for example, unless they explicitly say "limited record." They don't
include limited private non-tagged types, unless they have an access
discriminant with a default, etc.

I agree something like "inherently limited"
is what we want, but "the full type is limited"
is close enough, and probably a bit better in some ways, since it reduces how
far the user needs to look to decide whether the special case applies.

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

From: Bob Duff
Sent: Thursday, May 6, 2010  10:10 AM

> A suggestion Ed made in our internal discussion, is that the exception
> should depend on the limitedness of the type (not immutable
> limitedness) at the point of the subprogram declaration, on the
> grounds that the client should know if the exception applies.

Well, maybe, but you could use the same argument about lot of things.  For ex.,
you can't tell whether a type is by-copy or by-reference without peeking at the
private part.  You can't tell whether "X : Set;" initializes X to the empty set
without peeking.  (Or trusting comments.)

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  10:14 AM

> Well, maybe, but you could use the same argument about lot of things.
> For ex., you can't tell whether a type is by-copy or by-reference
> without peeking at the private part.  You can't tell whether "X :
> Set;" initializes X to the empty set without peeking.  (Or trusting
> comments.)

True, so that's not a consideration in this case

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  10:06 AM

I think the wording is adequate as is, since it is clearly talking about dynamic
semantics, where we are really talking about the deep-down properties.  We could
throw in "full type is limited" to be clearer.

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

From: Robert Dewar
Sent: Thursday, May 6, 2010  10:13 AM

> I think the wording is adequate as is, since it is clearly talking
> about dynamic semantics, where we are really talking about the
> deep-down properties.  We could throw in "full type is limited" to be
> clearer.

I think "full type is limited" is fine

Note that this means the client does not know if the exception applies, but I
think that's OK. The client should expect calls to be eliminated if the
arguments are the same, we are just pointing out a case where they might not be
the same even though they look like they are, but it would be wrong for a client
to rely on this in the way our customer is doing for instance.

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

From: Tucker Taft
Sent: Thursday, May 6, 2010  10:15 AM

Interesting.  It is certainly useful to
understand the user problem that led to
reviewing this wording.  Making it
depend on the limitedness at the point
of the declaration makes sense, I guess.

I agree that it shouldn't vary based
on the visibility at the point of call,
and this approach satisfies that goal.

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

From: Bob Duff
Sent: Thursday, May  6, 2010  10:32 AM

Customer wrote a subprogram that reads from a file, and declared that it's pure.
We have no idea why (and probably they don't either -- maybe the person who
wrote it is gone).  The subprogram has a parameter of a limited private type
whose full type is nonlimited. We have no idea whether this was a deliberate
attempt to invoke the "don't optimize if limited" rule we are discussing.

They were surprised that the second call didn't read the second item from the
file, but instead reused the first one.  But only at high optimization level.

After much going round and round, Robert told them they have to fix their code.

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

From: Robert Dewar
Sent: Thursday, May  6, 2010  11:01 AM

The user problem was that they had pure subprograms that did I/O, and were upset
that calls got eliminated.

Through what I am absolutely *sure* was an accident, the subprograms in question
have a parameter of a type that is limited, whose full declaration is not
limited.

Now GNAT was not paying attention to this restriction at all, so we implemented
the restriction, thinking that perhaps it would serendipitously make the (really
evidently wrong) code of the customer work by accident.

The customer for sure new nothing about this rule!

So we implemented it, but in a way that depended on the limitedness of the full
type, and that of course did not help the customer.

But really the customer code is just wrong here, I don't think it should figure
into our discussion.

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

From: Jean-Pierre Rosen
Sent: Thursday, May  6, 2010  12:07 PM

> Customer wrote a subprogram that reads from a file, and declared that
> it's pure.

But IO packages are not pure. They must have interfaced, or gone out of the
language at some point?

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

From: Bob Duff
Sent: Thursday, May  6, 2010  12:14 PM

Right, I forget the details, but it was some sort of roll-your-own I/O.

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

From: Robert Dewar
Sent: Thursday, May  6, 2010  12:23 PM

yes of course!

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

From: Randy Brukardt
Sent: Thursday, May  6, 2010  3:23 PM

Presuming they used pragma Import (which seems highy likely), their code is
erroneous by B.1(38.1/2) -- as I/O code (which is surely not pure) called from a
pure package surely "violates Ada semantics" (in this case the restriction to
Pure). So your compiler would be justified in generating any code whatsoever,
including calculating PI to 100,000 digits. :-)

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

From: Robert Dewar
Sent: Friday, May  7, 2010  8:11 AM

Yes, of course we know this, but that's not useful in dealing with customers, we
told them they had three reasonable alternatives

Turn off optimization
Make the type really limited
Stop declaring them pure

Clearly the third is best

But the point in the context of this discussion is that this was NOT a
legitimate use of the exception, so it should be ignored.

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

From: Gary Dismukes
Sent: Friday, May  7, 2010  12:26 PM

> I agree something like "inherently limited"
> is what we want, but "the full type is limited"
> is close enough, and probably a bit better in some ways, since it
> reduces how far the user needs to look to decide whether the special
> case applies.

Rather than just "the full type is limited", I think it would be better to
parallel the wording used to define the requirement for build-in-place in
7.6(17.2/3):

17.2/3   If the full type of any part of the object is immutably limited,
         the anonymous object is built in place.

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


Questions? Ask the ACAA Technical Agent