Version 1.3 of ai05s/ai05-0151-1.txt

Unformatted version of ai05s/ai05-0151-1.txt version 1.3
Other versions for file ai05s/ai05-0151-1.txt

!standard 3.10.1(2/2)          09-06-06 AI05-0151-1/03
!class Amendment 09-04-29
!status work item 09-04-29
!status received 09-04-29
!priority High
!difficulty Hard
!subject Allow incomplete types as parameter and result types
!summary
Make limited views of packages more useful by allowing more use of the incomplete types they make visible.
!problem
The limited with clause makes incomplete views of types visible. Tagged incomplete types are useful for formal parameters, but most other incomplete types are pretty much useless, except as the designated type of an access type. It would be nice if a type declared in a package named in a limited with clause could be used somehow, if only as a parameter type.
!proposal
Incomplete types may be used as formal parameter and result types, so long as they are fully defined at the point of call and at the point where the body is defined.
Incomplete types may not be used for components or objects.
For tagged incomplete types, we will continue to permit them as parameters even in calls and in a body, provided the incomplete type comes from a limited view of a package, rather than from an incomplete type declaration. For non-tagged incomplete types, they will not be permitted in calls or in a body. If the parameter or result type was incomplete at the point of declaration, any call or the body must be within the scope of a non limited view of the package defining the type.
!wording
** TBD **
!discussion
This proposal originally focused on a concern that a "limited with" naming a package with named access types forces the use of a lot of explicit conversion and/or anonymous access types in the clients. We originally proposed to allow "incomplete access types" to be used as formal parameters and result types, to avoid the need for all of the conversion. However, after analysis of the issues involved, it became clear that it was possible to generalize, and in some ways simplify, the proposal by allowing the use of any incomplete type as a parameter or result type, provided that the full definition was available at the point of call or at the definition of the body of the subprogram.
An incomplete type is OK as a parameter or result since, until there is a call, there is no need to know the representation of the type. This is in contrast to the case with components, where an aspect clause would need to be obeyed to ensure that streaming, aliased objects, etc., work as expected.
Currently compilers generally do know the representation of the parameters and result at the point of declaration of a subprogram (though not for access-to-subprogram declarations). However, it should be possible to handle the lack of such representation information by having the compiler implicitly create a local access-to-subprogram type at the point of call, and then call through that, using only the address of the subprogram with incomplete types in its declaration, while determining the parameter passing mechanism from the access-to-subprogram type.
Note that we have chosen to allow incomplete types as function results, even though we restricted tagged incomplete types to being parameters only. This seems inconsistent. Why should tagged incomplete types be more restrictive than incomplete types in general? Well, they shouldn't be, so with this proposal, the only advantage a tagged incomplete type will have is that a call or body will be permitted on a subprogram with tagged incomplete parameters, provided they are not controlling parameters. Tagged or untagged incomplete types will be permitted as both parameters and results when declaring a subprogram.
The net effect of this proposal is that changing a "with" to a "limited with" will be much less of a disruption for a client package, since it may continue to declare subprograms using the types from the limited-with'ed package. It won't be able to use those types as component types, but access types are frequently an adequate work-around in that case.
generic Formal Incomplete Types?
I wonder whether we could have generic formal incomplete types as a way to allow instantiation with a private type before it is completely defined. This might be sufficient for a "signature" generic.
!example
--!corrigendum 3.10.1(2/2)
!ACATS test
Add ACATS tests for this new feature.
!appendix

From: Tucker Taft
Sent: Saturday, June 6, 2009  3:58 PM

Here is an AI that came out of discussions about access types we have been
having over the past couple of months.  Basically it allows incomplete types as
parameter and result types, so long as at the point of call or the body the
types are fully defined.

This makes changing a "with" clause to a "limited with"
clause *much* less disruptive, since there is no need to change the
parameter/result profile of any subprograms declared in the client package just
because the types might be incomplete because they are coming from a limited
view of a package.

[This is version /03 of the AI, the earlier versions were merged into AI05-149 and eliminated here. - ED]

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

From: Bob Duff
Sent: Saturday, June 6, 2009  4:30 PM

> Here is an AI that came out of discussions about access types we have
> been having over the past couple of months.  Basically it allows
> incomplete types as parameter and result types, so long as at the
> point of call or the body the types are fully defined.

Seems like a big improvement to the language.  Ideally, access type should be
used only when you really want reference semantics.  This change moves closer to
that ideal.

> This proposal originally focused on a concern that a "limited with"
> naming a package with named access types forces the use of a lot of
> explicit conversion and/or anonymous access types in the clients.  We
> originally proposed to allow "incomplete access types" to be used as
> formal parameters and result types, to avoid the need for all of the
> conversion.  However, after analysis of the issues involved, it became
> clear that it was possible to generalize, and in some ways simplify,
> the proposal by allowing the use of *any* limited type as a parameter
> or
                                        ^^^^^^^ I think you mean "incomplete
                                       type from a limited-with'ed package".

[Corrected in the posted version /03, Editor.]

> result type, provided that the full definition was available at the
> point of call or at the definition of the body of the subprogram.
>
> An incomplete type is OK as a parameter or result since, until there
> is a call, there is no need to know the representation of the type.
> This is in contrast to the case with components, where an aspect
> clause would need to be obeyed to ensure that streaming, aliased
> objects, etc., work as expected.
>
> Currently compilers generally do know the representation of the
> parameters and result at the point of declaration of a subprogram
> (though not for access-to-subprogram declarations).

What's the acc-to-subp case you're referring to?

>... However, it should
> be possible to handle the lack of such representation information by
>having the compiler implicitly create a local access-to-subprogram type
>at the point of call, and then call through that, using only the
>address  of the subprogram with incomplete types in its declaration,
>while determining  the parameter passing mechanism from the access-to-subprogram type.
>
> Note that we have chosen to allow incomplete types as function
> results, even though we restricted tagged incomplete types to being
> parameters only.  This seems inconsistent.  Why should tagged
> incomplete types be
> *more* restrictive than incomplete types in general? Well, they
> shouldn't be, so with this proposal, the only advantage a tagged
> incomplete type will have is that a call or body *will* be permitted
> on a subprogram with tagged incomplete parameters, provided they are
> not controlling parameters.  Tagged or untagged incomplete types will
> be permitted as both parameters and results when declaring a subprogram.
>
> The net effect of this proposal is that changing a "with" to a "limited with"
> will be much less of a disruption for a client package, since it may
> continue to declare subprograms using the types from the limited-with'ed package.
> It won't be able to use those types as component types, but access
> types are frequently an adequate work-around in that case.

That seems like a secondary benefit.  The primary benefit is that when you use
"limited with" (in the first place) you don't have to use pointers when you
don't want pointer semantics.  I'd say that first, then ``In addition, changing
a "with" to a "limited with"...''.

> Generic Formal Incomplete Types?
>
> I wonder whether we could have generic formal incomplete types as a
> way to allow instantiation with a private type before it is completely
> defined.  This might be sufficient for a "signature"
> generic.

Interesting idea.

Does the "use package Blah" thing provide a different way to do signature
generics?

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

From: Tucker Taft
Sent: Sunday, June 7, 2009  6:15 AM

> ...  However, after analysis of the issues involved, it became
>> clear that it was possible to generalize, and in some ways simplify,
>> the proposal by allowing the use of *any* limited type as a parameter
>> or
>                                         ^^^^^^^ I think you mean
> "incomplete type from a limited-with'ed package".

Right you are.

 > ...
>> Currently compilers generally do know the representation of the
>> parameters and result at the point of declaration of a subprogram
>> (though not for access-to-subprogram declarations).
>
> What's the acc-to-subp case you're referring to?

You are allowed to use incomplete types as parameter or result types in an
access-to-subprogram type declaration.

> ...
>> Generic Formal Incomplete Types?
>>
>> I wonder whether we could have generic formal incomplete types as a
>> way to allow instantiation with a private type before it is
>> completely defined.  This might be sufficient for a "signature"
>> generic.
>
> Interesting idea.
>
> Does the "use package Blah" thing provide a different way to do
> signature generics?

Yes, by putting most of the content of a (generic) package into an "integrated"
subpackage, you can then follow the integrated subpackage with one or more
generic instantiations, which are allowed to use private types defined in the
integrated subpackage.

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

From: Tucker Taft
Sent: Saturday, June 6, 2009  3:24 PM

I'm trying to figure out what is currently allowed for subprograms with
parameters of a tagged incomplete type.  Calling a subprogram freezes its
profile, and freezing its profile freezes all of its parameter types.  What
happens when you freeze a tagged incomplete type?  Isn't that illegal if the
type isn't completely defined?

Are incomplete types produced by a limited view of a package "completely
defined" everywhere, so that freezing them is OK?  I presume that freezing an
incomplete type that is defined by an incomplete type declaration is illegal if
it happens in a place outside the scope of the full definition.

I am going to proceed in my work on AI05-0151 presuming that it is OK to freeze
an incomplete type coming from the limited view of a package, and it has no
effect, while freezing an incomplete type defined by an incomplete type
declaration would be illegal outside the scope of the full type definition.

I suspect this question needs a more explicit answer somewhere in the RM, or at
least in the AARM.

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

From: Bob Duff
Sent: Saturday, June 6, 2009  4:33 PM

...
> I suspect this question needs a more explicit answer somewhere in the
> RM, or at least in the AARM.

I'm puzzled by this message.  The version of AI05-0151-1v3 you just sent says
you can't call a subp or give its body, until you have completion. Isn't that
obviously necessary?

Maybe if you gave an example of what you're asking, as in "Should the following
be legal?"...

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

From: Randy Brukardt
Sent: Saturday, June 6, 2009  9:56 PM

> I'm trying to figure out what is currently allowed for subprograms
> with parameters of a tagged incomplete type.
> Calling a subprogram freezes its profile, and freezing its profile
> freezes all of its parameter types.  What happens when you freeze a
> tagged incomplete type?  Isn't that illegal if the type isn't
> completely defined?

13.14(17): "A type shall be fully defined before it is frozen." So, yes, of
course, that is illegal.

> Are incomplete types produced by a limited view of a package
> "completely defined" everywhere, so that freezing them is OK?
>  I presume that freezing an incomplete type that is defined by an
> incomplete type declaration is illegal if it happens in a place
> outside the scope of the full definition.

I don't think this matters; either the completion exists (in which case it is
fine to freeze it elsewhere) or it does not.

I surely would expect that all entities imported by with clauses are considered
frozen. That doesn't appear to be an explicit rules, but it is true because the
exported entities are all frozen by the end of the spec. Since all views are
frozen at once, that surely must include any exported incomplete views in the
limited view of the package. QED. :-)

And in this case, Robert's rule of absurdity would apply: if tagged limited
views imported by with clauses were *not* frozen, it would be impossible to use
them in subprogram parameters. Which would make all of the effort to define that
moot. That's an absurd result.

The AARM notes added by AI05-0017-1 (13.14(3.b-3.b.1/3)) sort of address this
topic. but don't explicitly mention limited views. Probably we ought to add an
AARM note to mention this meta-rule (probably in the Language Design
Principles).

Unrelated aside: 13.14(1.j) is misleading, as all of these entities have
freezing and get frozen at particular points (for Convention and address clauses
at least); I think the point of the note is that we don't use freezing per-se to
handle most issues of premature access. Probably ought to be rewritten.

> I am going to proceed in my work on AI05-0151 presuming that it is OK
> to freeze an incomplete type coming from the limited view of a
> package, and it has no effect, while freezing an incomplete type
> defined by an incomplete type declaration would be illegal outside the
> scope of the full type definition.

That would be correct.

> I suspect this question needs a more explicit answer somewhere in the
> RM, or at least in the AARM.

I think an AARM note is enough, since it clearly (!) follows from the existing
freezing rules. But I would agree that it isn't obvious.

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

From: Tucker Taft
Sent: Sunday, June 7, 2009  6:21 AM

...
> I'm puzzled by this message.  The version of AI05-0151-1v3 you just
> sent says you can't call a subp or give its body, until you have completion.
> Isn't that obviously necessary?

The issue is with the *current* rules that allow the use of tagged incomplete
types as parameters. Can these be incomplete at the point of call or the body,
provided they came from the limited view of a package?

> Maybe if you gave an example of what you're asking, as in "Should the
> following be legal?"...

OK:

     package P is
        type T is tagged null record;
     end P;

     limited with P;
     package Q is
        procedure M(X : P.T);
        type Acc is access T;
     end Q;

     -- NOTE: no "with" of P here
     package body Q is
        procedure M(X : P.T) is ... -- legal?

        Y : Acc;

     begin
        M(Y.all);  -- legal?
     end Q;

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

From: Bob Duff
Sent: Sunday, June 7, 2009  8:12 AM

OK, I see what you're getting at.

Both of the above had better be illegal, right?
Y has to be null, but we plugged a hole like that in Ada 83.

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

From: Tucker Taft
Sent: Sunday, June 7, 2009  8:29 AM

> Both of the above had better be illegal, right?

No, I think our intent was that both of the above would be *legal*, since we
know that tagged types are passed by reference, and so there is no problem
passing them around even if you don't know anything about them.

> Y has to be null, but we plugged a hole like that in Ada 83.

I should have thrown in some "..." since my presumption was that Y might have
been initialized by calling some function that returned an Acc.  That function
would presumably be in another package which *does* have a non-limited "with" of
P, and can legally do an allocator to create a non-null Acc value.

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

From: Randy Brukardt
Sent: Sunday, June 7, 2009  9:38 PM

> > Both of the above had better be illegal, right?
>
> No, I think our intent was that both of the above would be *legal*,
> since we know that tagged types are passed by reference, and so there
> is no problem passing them around even if you don't know anything
> about them.

That is my understanding as well. That is why 3.10(10/2) talks about *prefixes*
that are of incomplete views, as opposed to *names* that are of incomplete
views. The call cannot be a dispatching call (since we don't know where the tag
is), but a simple "pass-through" call is allowed.

OTOH, we can't support that for untagged types (because we don't know how
they're passed) or for function results (since they are creating a new object,
even for tagged types). So it seems that Tucker cannot rely solely on the
freezing rules to implement the completeness check here.

(That appears to be the difference between tagged and untagged incomplete types
in this scheme, along with the use of 'Class: that you can declare bodies and
make calls with tagged incomplete parameters/objects, but not with untagged
incomplete.)

> > Y has to be null, but we plugged a hole like that in Ada 83.
>
> I should have thrown in some "..." since my presumption was that Y
> might have been initialized by calling some function that returned an
> Acc.  That function would presumably be in another package which
> *does* have a non-limited "with" of P, and can legally do an allocator
> to create a non-null Acc value.

Right, that was the idea. If a package is just passing a tagged object from one
package to another, there is no need to know any details about the type, and, as
Bob mentioned in another message, we don't want to force using access types
unless the reference semantics are actually needed.

I'm not sure this really works very well in practice, but it surely was intended
to be possible.

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


Questions? Ask the ACAA Technical Agent