Version 1.6 of ai05s/ai05-0232-1.txt

Unformatted version of ai05s/ai05-0232-1.txt version 1.6
Other versions for file ai05s/ai05-0232-1.txt

!standard 7.6(17.1/3)          11-01-27 AI05-0232-1/02
!class ramification 11-01-27
!status ARG Approved 6-0-2 11-02-20
!status work item 10-10-25
!status received 10-09-24
!priority Low
!difficulty Easy
!subject Hole in AI05-0067-1
!summary
Whether a call is required to be built-in-place is a dynamic property of the object.
!question
Is the following call built-in-place?
type Interface_Type is limited interface;
Obj : Interface_Type'Class := Some_Function(...);
where Some_Function is declared as returning Interface_Type'Class. Interface_Type'Class is not immutably limited, since a type derived from Interface_Type could be limited or nonlimited (AARM 7.5(8.c)). This would seem to mean that it's unspecified whether this function call is built in place, since the rule in 7.6(17.2) refers to the (full) type of the object, not to the type determined by the tag of the function result.
But this doesn't seem desirable, since the function result could be of a limited type, and in that case we still want to have the result built in place, with no copying.
Is a fix needed? (No.)
!recommendation
(See summary.)
!wording
Add after 7.6(17.2/3):
AARM To Be Honest: This is a dynamic property and is determined by the specific type of the parts of the actual object. In particular, if a part has a class-wide type, the tag of the object might need to be examined in order to determine if build-in-place is required. However, we expect that most Ada implementations will determine this property at compile-time using some assume-the-worst algorithm in order to chose the appropriate method to implement a given call or aggregate. In addition, there is no attribute or other method for a program to determine if a particular object has this property (or not), so there is no value to a more careful description of this rule.
!discussion
RM 7.6 states:
When a function call or aggregate is used to initialize an object, the result of the function call or aggregate is an anonymous object, which is assigned into the newly-created object. For such an assignment, the anonymous object might be built in place. Under certain circumstances, the anonymous object is required to be built in place, in which case the assignment does not involve any copying. In particular:
If the full type of any part of the object is immutably limited, the anonymous object is built in place.
...
One part of any object is the object itself, so this rule implies that build-in-place is required if the full type of the object is immutably limited.
But because this wording is under "Dynamic Semantics", 3.1(7/3) does not apply and thus views are not involved here. For a given part, this wording refers to the specific nonabstract type of the part. Also note that parts other than the object itself cannot be class-wide (as indefinite components are not allowed); thus there always is a specific type.
In the case that the object itself has a class-wide type (as opposed to a specific tagged type), this wording refers to the type identified by the tag of the part.
In the case of a function returning Some_Limited_Interface_Type'Class, build-in-place is required if and only if the specific nonabstract type of the function result is immutably limited.
This means that for two different elaborations of the object declaration given in the question, one call to Some_Function might require build-in-place while the other might not. As a practical matter, an implementation is likely to chose to build-in-place all objects returned from calls to Some_Function -- but this is not required.
!ACATS Test
No ACATS test is needed.
!ASIS
No effect on ASIS.
!appendix

!topic Possible hole in AI05-0067?
!reference 7.6(17.1/3-17.4/3)
!from Adam Beneschan 10-09-24
!discussion

I've just now found a reason to look over the new build-in-place rules, and I've
run into something that may be an important omission.

The new rules say that, for a function call used to initialize an object, the
function call must be built in place if the object's type is immutably limited,
but it's unspecified whether it's built in place in other cases.

What happens in this case?

   type Interface_Type is limited interface;

   Obj : Interface_Type'Class := Some_Function(...);

where Some_Function is declared as returning Interface_Type'Class.
Interface_Type'Class is not immutably limited, since a type derived from
Interface_Type could be limited or nonlimited (AARM 7.5(8.c)). This would seem
to mean that it's unspecified whether this function call is built in place,
since the rule in 7.6(17.2) refers to the (full) type of the object, not to the
type determined by the tag of the function result.

But this doesn't seem desirable, since the function result *could* be of a
limited type, and I'd think that in this case we still want to have the result
built in place, with no copying.

Should 7.6(17.1-17.4) be modified to require build in place when an object type
is the 'Class of a limited interface type?  I don't think this would be harmful
in cases where the function result is actually a nonlimited type (see the last
sentence of AARM 7.6(17.o)), but maybe there are cases where it would be a
problem.  (An alternative would be to require implementations to build the
result in place if the function result's tag identifies a limited type, and let
them choose if it identifies a nonlimited type.  But from my point of view, in
our implementation, generating code to decide this at runtime isn't feasible.)

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

Following is the edited end of a private conversation about this AI:

Randy Brukardt:

Thanks. I turned this into a complete AI. But you've made me dubious 
of the conclusion that we came to. I think we need *at least* an 
AARM To-Be-Honest note (in which case this is a Ramification) or a 
bit of full-blown wording (in which case it is a BI), because the 
leap that you use to assume we use the tag doesn't make much sense.

Steve Baird:

Oh dear, we seem to have exchanged positions.

I thought the conclusion made sense. The point is that when we are talking
about the type of an arbitrary part of an object in a dynamic semantics check,
and if that part happens to be tagged, we (as you explained to me) couldn't
very well be talking about anything other than specific, nonabstract type
associated with the part's tag.

This is unchanged if the part we happen to be considering (as part of a rule
that applies to all parts of an object) is the object itself.

The object's (nominal) type might be abstract and/or classwide, but that's
irrelevant.

Randy Brukardt:

The conclusion makes sense. But it doesn't match the way the standard is written.
And I was explaining to you that you always look at the type of the parts of the
actual returned object, not of the nominal type of the function. I had incorrectly
convinced myself that that never required inspection of the tag (see below).
 
I definitely agree that we don't care about the nominal subtype. But go back and
read AI05-0099-1 again.

It concludes:
(1) The standard does not define a "dynamic type".
(2) The standard always specifies when the tag needs to be consulted to determine
    a property.
Ergo, we needed to make a wording change for that AI.

The same applies here. Yesterday, I thought that you always knew that type somewhere,
because components cannot have class-wide types, and the types of parts are only
(logically) consulted when the return statement is executed. For an abstract
class-wide type as in the example, you have to be returning an object that is of
some other specific type (so you know the type there). No tag reading needed in either
case.

But I forgot that you could also return some sort of class-wide object (either a
stand-alone object or another function call); if that object has no inherently limited
parts, then there is nowhere else to look; while that is unusual it is possible, and
in those cases you'd probably need to consult the tag. If you need to consult the tag,
we need wording (or at least a To Be Honest note).

The problem that the ARG has had is that we were focusing on Adam's question. His
question is bogus, because this is a dynamic property that doesn't necessarily get
determined until the instant that the return statement starts returning the object.
It is inspection of the returned object, and not anything about the properties of the
function, that determines whether build-in-place is required. So there is no problem at
the call site (which is what he asked): the function (and its call) has to be able to
return a object that is build-in-place, but it only has to do that if the actual object
requires that.

But there still is a problem *inside* the function with the inspection of the returned
object. The model is correct, but to properly use that model we need some wording --
because there is no such thing as a dynamic type. And we all agree that we're not (only)
looking at the nominal type of the parts of that object (the subtype is irrelevant of
course).

I think just a To Be Honest note would be sufficient, because "requires build-in-place"
is not a property that you can query -- thus being unambiguous about the runtime value
is not that critical. All an implementation has to do is ensure that no case that
"requires build-in-place" is copied; it is perfectly OK to build-in-place cases that
do not need to be handled that way. But I think we do need to mention in the standard
that you might have to query the tag to determine this property -- or "assume-the-worse"
about class-wide objects. That means this is a ramification and not a confirmation,
and thus it has to be rewritten again.

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

Questions? Ask the ACAA Technical Agent