Version 1.4 of ai05s/ai05-0059-1.txt

Unformatted version of ai05s/ai05-0059-1.txt version 1.4
Other versions for file ai05s/ai05-0059-1.txt

!standard 7.5(8.1/2)          08-02-24 AI05-0059-1/03
!standard 7.5(8.1/2)
!class binding interpretation 07-08-03
!status work item 07-08-03
!status received 07-06-25
!priority Medium
!difficulty Easy
!qualifier Error
!subject Limited derived types and build-in-place
!summary
Types that are immutably limited are build-in-place types.
!question
package Pack1 is type Typ1 is tagged limited record F1 : Integer; F2 : Integer; end record; end Pack1;
with Pack1; package Pack2 is type Typ2 is new Pack1.Typ1 with record F3 : Integer; end record; function Func (Z : Integer) return Typ2; end Pack2;
with Pack2; procedure Proc is X : Pack2.Typ2 := Pack2.Func (123); -- built-in-place? begin ... end;
Does the language require Func to build its result in place?
It would seem that it should; if an anonymous object were created, you'd be copying a Typ1 along with F3, which should be a no-no. But, since I have this ridiculous habit of trying to read the RM literally, it seems to me that the rules as written don't actually require the function result to be built in place. Here's how I read it:
The Implementation Requirement in 7.5(8.1) says that when a function call is used to initialize an object, and the function call has a type "with a part that is of a task, protected, or explicitly limited record type", build-in-place is required.
Typ2, however, is not an explicitly limited record type. This is defined in 3.8(13.1) to be a record_type_definition that includes the reserved word "limited", and the definition of Typ2 doesn't include the word "limited" in it anywhere. There is nothing in the RM that says a type extension derived from an "explicitly limited" record type is also explicitly limited.
Should this type be build-in-place? (Yes.)
!recommendation
(See Summary.)
!wording
Modify 7.5(8.1/2) ... For a function_call of a type {whose full type is an immutably limited type}[with a part that is of a task, protected, or explicitly limited record type that is used to initialize an object as allowed above], the implementation shall not create a separate return object (see 6.5) for the function_call.
AARM Note: Like parameter passing, this ignores privacy; thus we say "full type is an immutably limited type".
!discussion
A similar example can be constructed for an untagged record type:
type Lim is limited record Self : access Lim := Lim'access; end record;
type Foobar is new Lim;
function Do_It return Foobar; -- Better be build-in-place!!
We surely don't want objects of type Foobar to be copied by a function return, but the hole applies here, too: there is no keyword limited in the declaration of type Foo.
We could have fixed this problem with additional words in 7.5(8.1/2), but that would just be leaving the problem to reappear again. We always want derived types to have the same properties as their parent type, so having to add "a descendent of" before every use of "explicitly limited record type" is just asking for trouble.
Indeed, this problem is severe enought that AI05-0052-1 defines "immutably limited type" (which includes descendants, of course). Having defined this term, we simply change 7.5(8.1/2) to use this term.
!corrigendum 7.5(8.1/2)
Replace the paragraph:
For an aggregate of a limited type used to initialize an object as allowed above, the implementation shall not create a separate anonymous object for the aggregate. For a function_call of a type with a part that is of a task, protected, or explicitly limited record type that is used to initialize an object as allowed above, the implementation shall not create a separate return object (see 6.5) for the function_call. The aggregate or function_call shall be constructed directly in the new object.
by:
For an aggregate of a limited type used to initialize an object as allowed above, the implementation shall not create a separate anonymous object for the aggregate. For a function_call of a type whose full type is an immutably limited type that is used to initialize an object as allowed above, the implementation shall not create a separate return object (see 6.5) for the function_call. The aggregate or function_call shall be constructed directly in the new object.
!ACATS Test
!appendix

!topic Limited type extensions and build-in-place
!reference RM 3.2(6), 3.8(13.1), 7.5(8.1)
!from Adam Beneschan 07-06-25
!discussion

package Pack1 is
    type Typ1 is tagged limited record
        F1 : Integer;
        F2 : Integer;
    end record;
end Pack1;

with Pack1;
package Pack2 is
    type Typ2 is new Pack1.Typ1 with record
        F3 : Integer;
    end record;
    function Func (Z : Integer) return Typ2;
end Pack2;


with Pack2;
procedure Proc is
    X : Pack2.Typ2 := Pack2.Func (123);  -- built-in-place?
begin
    ...
end;

Does the language require Func to build its result in place?

It would seem that it should; if an anonymous object were created,
you'd be copying a Typ1 along with F3, which should be a no-no.  But,
since I have this ridiculous habit of trying to read the RM literally,
it seems to me that the rules as written don't actually require the
function result to be built in place.  Here's how I read it:

The Implementation Requirement in 7.5(8.1) says that when a function
call is used to initialize an object, and the function call has a type
"with a part that is of a task, protected, or explicitly limited
record type", build-in-place is required.

Typ2, however, is not an explicitly limited record type.  This is
defined in 3.8(13.1) to be a record_type_definition that includes the
reserved word "limited", and the definition of Typ2 doesn't include
the word "limited" in it anywhere.  I can't find anything in the RM
that says a type extension derived from an "explicitly limited" record
type is also explicitly limited.  (It's not in 3.9.1; if it's
somewhere else, the index entry for "explicitly limited" doesn't point
to it.)

Also, I don't think Typ2 has a *part* that is an explicitly limited
record type.  "Part" is defined in 3.2(6): "Similarly, a _part_ of an
object or value is used to mean the whole object or value, or any set
of its subcomponents."  Even though an object of type Typ2 contains a
portion has Typ1, I don't think this meets the definition of "part".
A Typ2 doesn't have a component or subcomponent of type Typ1; and
while the "set of its subcomponents" phrase means that the set {F1,
F2} would be a "part" of a Typ2 object, to me there is a definite
distinction between the type Typ1 and the subcomponent set {F1, F2}.
In my opinion, it would be a real stretch to use that phrase to claim
that a Typ1 is a "part" of a Typ2.

So based on that, an object of thpe Typ2 doesn't meet the language of
7.5(8.1) and therefore the Implementation Requirement does not apply.

(I haven't looked at types derived from untagged limited types very
closely, but might those not have the same problem?)

Assuming that I haven't missed something and that my analysis is
correct, and that it was the intent that the Implementation
Requirement should apply to such type extensions, the best solution is
probably to change 7.5(8.1) to say "with a part that is of a task or
protected type or a type that is a descendant of an explicitly limited
record type".  (I haven't checked to make sure this would be good
enough to deal with generic formal limited types.)  This would still
conform to the rationale given in AARM 7.5(8.a/2): "For a
function_call, we only require build-in-place for a limited type that
would have been a return-by-reference type in Ada 95", since types
descended from explicitly limited types were return-by-reference (RM95
6.5(11)). 

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

From: Robert A. Duff
Sent: Saturday June 30, 2007  9:22 AM

...
> Does the language require Func to build its result in place?
> 
> It would seem that it should;

Certainly true.

...
> So based on that, an object of thpe Typ2 doesn't meet the language of
> 7.5(8.1) and therefore the Implementation Requirement does not apply.

This does seem like a hole in the wording.

> (I haven't looked at types derived from untagged limited types very
> closely, but might those not have the same problem?)
> 
> Assuming that I haven't missed something and that my analysis is
> correct, and that it was the intent that the Implementation
> Requirement should apply to such type extensions, the best solution is
> probably to change 7.5(8.1) to say "with a part that is of a task or
> protected type or a type that is a descendant of an explicitly limited
> record type".  (I haven't checked to make sure this would be good
> enough to deal with generic formal limited types.)

Generics are irrelevant.  Building in place happens at run-time, so the type
we're talking about is the actual type passed in to the generic.  One instance
might use b-i-p, and the other not.

>...  This would still
> conform to the rationale given in AARM 7.5(8.a/2): "For a
> function_call, we only require build-in-place for a limited type that
> would have been a return-by-reference type in Ada 95", since types
> descended from explicitly limited types were return-by-reference (RM95
> 6.5(11)).

I think that rationale is intended to be stronger -- the b-i-p types are
intended to be exactly the types that were ret-by-ref in Ada 95.  (Ret-by-ref
was a nasty language design mistake, by the way.  I wish JDI had invented
b-i-p in 1980.)

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




Questions? Ask the ACAA Technical Agent