Version 1.4 of ais/ai-00389.txt

Unformatted version of ais/ai-00389.txt version 1.4
Other versions for file ais/ai-00389.txt

!standard 4.3.1(8)          04-12-03 AI95-00389/03
!standard 4.3.1(16)
!standard 4.3.1(17)
!standard 4.3.2(4)
!standard 4.3.2(5)
!class amendment 04-11-11
!status No Action (10-0-0) 05-02-12
!status work item 05-02-07
!status ARG Approved 5-0-5 04-11-20
!status work item 04-11-11
!status received 04-11-11
!priority Medium
!difficulty Medium
!subject Allow aggregates of partial views
!summary
An aggregate of a partial view is allowed; such an aggregate must contain "others => <>" to default initialize the components only known to the full view. Similarly, aggregates of task types, protected types, and private extensions are allowed.
!problem
AI95-00287 introduces the <> (box) notation for default initializing components of an aggregate. This can be used on any type. However, aggregates of a partial view (which is considered to be a composite type) are not allowed. Default-initialized aggregates of a partial view should be allowed.
Default-initialized aggregates are especially useful to define constants (which are required to be initialized) outside of the defining package of a private type. They also can be useful to explicitly show that the default initialization of an object is intended and important to proper functioning of a program.
!proposal
Allow record aggregates to be of any non-array composite type. For partial views, the needed components still are those of the full view, even though the components of the full view cannot be named. An aggregate of a partial view must include "others => <>"; this is needed to avoid any dependence on the components of the full view.
Note that if known discriminants are given for the type, they can be specified along with "others => <>".
Similar rules apply to generic formal types that are composite, task types, and protected types. We also have similar rules for extension aggregates of partial extensions.
!wording
The wording of this AI assumes the wording changes of AI-287 have been applied.
Change 4.3(3):
The expected type for an aggregate shall be a single composite type.
Change 4.3.1(8):
The expected type for a record_aggregate shall be a single non-array composite type.
[Note to Gary: "non-array" occurs in normative wording in 4.1.3(7) and 13.5.2(1); "nonarray" does not occur in the AARM.]
4.3.1(9) is unchanged. Add an additional AARM note to the end of the paragraph:
Ramification: For a partial view, all of the components of the full type are needed, even though not all of them can be named in the aggregate. For a generic formal type, all of the components of the actual type are needed, even though not all of them can be named in the aggregate.
Modify the start of 4.3.1(16) to:
Each record_component_association {other than an OTHERS choice with a <>} shall have at least one associated component...
Modify the AARM Note 4.3.1(16.a): These rules apply to an association with an others choice {with an expression}. {An others choice with a <> can match a null record type or a null extension.}
[Author's Note: This is needed so that an others choice for a partial view can match a null record full type. This is required so that we don't "leak" information about the full type to the uses. I believe that this is really a bug in AI-287 anyway; a default-initializing others should be allowed to match nothing, as it is harmless (by using OTHERS you've turned off completeness checking anyway) and useful.]
Add after 4.3.1(17.1): (The new Legality Rule added by AI-287)
If the type of the record_aggregate is a partial view of a type, a task type, a protected type, a formal private type, or a formal derived type:
* The record_component_association_list shall include OTHERS => <>; and
AARM Note: Reason: For partial views and generic formals, this is needed to avoid "leaking" information about the full type to the aggregate. Without this rule, if the full type was NULL RECORD, NULL RECORD could be used; and if the full type had only one component, OTHERS => some-expression could be used. That would clearly break privacy. Similar issues apply to formal types; if information about the actual type could be used in the aggregate, we'd have a generic contract issue. Since each component can only occur in a single association, this rule prevents those issues.
For tasks and protected types, this recognizes that there may be components (such as the lock for a protected type) that are only known to the implementation; these components necessarily have to be given default initialization. For portability, we don't want aggregates to be written that depend on whether the implementation has such components.
* The type of the record_aggregate shall have known discriminants or be a tagged, task, or protected type that does not have unknown discriminants; and
AARM Note: Reason: We only want to allow aggregates of partial views when the full type is certain to be composite. Otherwise, we would have anomalies where additional visibility would cause the ability to have aggregates to disappear (if the full type is elementary). That's true if the partial view has known discriminants or is tagged. Task and protected types are also allowed, as they are always composite. We also disallow types with unknown discriminants. Unknown discriminants are often used to prevent uncontrolled initialization of objects, and we don't want to provide an uncontrolled initialization mechanism for such types.
* The record_component_association_list shall not include a positional component association.
AARM Note: Reason: Otherwise, positional notation could be used to give associations for components of the full view that are not visible to the aggregate. That would be bad. We disallow positional notation completely to avoid confusion; this shouldn't be a hardship since typically there will be no more than a couple discriminants along with OTHERS => <> in such an aggregate.
Replace "record extension" in 4.3.2(4) to "type extension".
Modify 4.3.2(5):
If the ancestor_part is a subtype_mark, it shall denote a specific tagged subtype. The type of the extension_aggregate shall be {a descendant of} [derived from] the type of the ancestor_part[, through one or more record extensions (and no private extensions)]. {If the type of the extension_aggregate is derived from the type of the ancestor_part through one or more private extensions, then the record_component_association_list shall include OTHERS => <>, and shall not include a positional component association.}
AARM Note: Reason: We allow the type of the ancestor_part to be the type itself, so that these are allowed for generic formal derived types, where the actual type might be the same as the ancestor type.
If the type involves any private extensions, we require the use of OTHERS => <> and disallow positional associations in order to avoid breaking privacy of the extensions. See 4.3.1 for a more complete discussion.
!discussion
This capability is a natural extension to that provided by AI-287. It is especially odd that such initializations are allowed in larger aggregates, just not for a complete object. For instance, given that Priv is a tagged private type:
type Wrapper is record P : Priv; end record;
Obj1 : constant Priv := (others => <>); -- Illegal by AI-287, allowed here. Obj2 : constant Wrapper := (others => <>); -- Legal by AI-287.
In order to avoid the anomaly of having an aggregate be legal for a partial view but not the full view, aggregates are not allowed for partial views that could be completed with an elementary type. Also to avoid that anomaly, we have to provide aggregates for task and protected types (as these are composite types which otherwise would not have aggregates).
We have to disallow any way to give a component of the full view without naming it in one of these new aggregates. To do that, we disallow positional notation, and OTHERS => <> is required.
In order to make this work cleanly, we need to define aggregates for (nearly) all composite types. Thus, we added aggregates of task and protected types. These also always require OTHERS => <>, as a task or protected object usually will have implementation-defined components that cannot be named. As with partial views, we do not want to expose the actual implementation in an aggregate.
We also define similar capabilities and restrictions for extension aggregates when one or more private extensions is involved.
!example
(See discussion.)
!corrigendum 4.3(3)
Replace the paragraph:
The expected type for an aggregate shall be a single nonlimited array type, record type, or record extension.
by:
The expected type for an aggregate shall be a single composite type.
!corrigendum 4.3.1(8)
Replace the paragraph:
The expected type for a record_aggregate shall be a single nonlimited record type or record extension.
by:
The expected type for a record_aggregate shall be a single non-array composite type.
!corrigendum 4.3.1(16)
Replace the paragraph:
Each record_component_association shall have at least one associated component, and each needed component shall be associated with exactly one record_component_association. If a record_component_association has two or more associated components, all of them shall be of the same type.
by:
Each record_component_association other than an others choice with a <> shall have at least one associated component, and each needed component shall be associated with exactly one record_component_association. If a record_component_association with an expression has two or more associated components, all of them shall be of the same type.
!corrigendum 4.3.1(17)
Insert after the paragraph:
If the components of a variant_part are needed, then the value of a discriminant that governs the variant_part shall be given by a static expression.
the new paragraphs:
If the type of the record_aggregate is a partial view of a type, a task type, a protected type, a formal private type, or a formal derived type:
!corrigendum 4.3.2(4)
Replace the paragraph:
The expected type for an extension_aggregate shall be a single nonlimited type that is a record extension. If the ancestor_part is an expression, it is expected to be of any nonlimited tagged type.
by:
The expected type for an extension_aggregate shall be a single type that is a type extension. If the ancestor_part is an expression, it is expected to be of any tagged type.
!corrigendum 4.3.2(5)
Replace the paragraph:
If the ancestor_part is a subtype_mark, it shall denote a specific tagged subtype. The type of the extension_aggregate shall be derived from the type of the ancestor_part, through one or more record extensions (and no private extensions).
by:
If the ancestor_part is a subtype_mark, it shall denote a specific tagged subtype. The type of the extension_aggregate shall be a descendant of the type of the ancestor_part. If the type of the extension_aggregate is derived from the type of the ancestor_part through one or more private extensions, then the record_component_association_list shall include others => <>, and shall not include a positional component association.
!ACATS test
ACATS tests need to be constructed to check that aggregates of partial views are allowed and allow the inclusion of discriminant values.
!appendix

From: Randy Brukardt
Sent: Wednesday, November 10, 2004  1:53 PM

I think it would be important if it worked for private types (which are by far
the most common); it's not very interesting for non-limited records, as the
default initialization is available anyway.

It's unfortunate that (<>) is not *always* a shorthand for default
initialization.

   Cnst : constant Priv := (<>);

comes up periodically; moreover, I would much prefer to be able to explicitly
initialize everything (that's currently not possible for private types that you
want or must use the default initialization for).

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

From: Tucker Taft
Sent: Wednesday, November 10, 2004  2:26 PM

I believe we always disallow use of "(<>)" so presumably you
meant "(others => <>)".  Allowing this for private types
would seem to be reasonable, since we consider them to
be "composite" types.  If they have visible discriminants,
then presumably we would allow "(Discrim => X, others => <>)".
I think the danger would be that if the private type turned
out to be a non-composite type in its full definition, the
notation "(others => <>)" would be legal only where you
have a *partial* view, which is somewhat unpleasant.

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

From: Randy Brukardt
Sent: Wednesday, November 10, 2004  6:36 PM

Yes, that is a bit unpleasant, although I would claim it is because there
exist types that you can't give aggregates. Doesn't seem like a big deal
though.

A quick look at the Standard suggests that the best place to put the needed
wording would be under record aggregates. The important features are:

The type of an aggregate can be a partial view of a type.

For a record_aggregate for a partial view, all components of the type are
*needed* [(but only known discriminants can be named)].

AARM To Be Honest: If the full view of the type is not composite, it is
thought of as a record containing one component of the full type.

If the type is a partial view, the following additional Legality Rules
exist:

* The partial view shall not have unknown discriminants.
* The aggregate shall include others => <>.

Comments?

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

From: Randy Brukardt
Sent: Wednesday, November 10, 2004  6:44 PM

BTW, the justification for allowing aggregates of private types would be that
you're allowed to default initialize them *inside* of a larger aggregate, it
seems silly to not allow it on a complete stand-alone object. That is, given
Priv is a private type:

    type Wrapper is record
       P : Priv;
    end record;

    Obj1 : constant Priv := (others => <>); -- Illegal by AI-287.
    Obj2 : constant Wrapper := (others => <>); -- Legal by AI-287.

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

From: Gary Dismukes
Sent: Wednesday, November 10, 2004  7:18 PM

That's a convincing justification for allowing it, and the partial view
issue doesn't seem like a major stumbling block (i.e., it could reasonably
be resolved along the lines you suggested in your other message).

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

From: Pascal Leroy
Sent: Thursday, November 11, 2004  1:14 PM

I hate to bring that up, but: what about generic formal private types?  It
you allow aggregates for those (which would seem consistent) the compilers
which do macro-expansion might end up with aggregates of an elementary
type.  That gives me the willies.

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

From: Randy Brukardt
Sent: Thursday, November 11, 2004  1:34 PM

I don't see why; such an aggregate means "default-initialize", which usually
means do nothing at all. I'd much prefer that (others => <>) worked for *all*
types, but given that it usually would mean "do nothing" for an elementary type
(something we certainly don't want to encourage by giving a way to write it), I
didn't propose that.

In any case, this proposal means that having aggregates of an elementary type
is a possibly (if the full type is elementary), so I don't think that there is
any additional hardship offered by a generic formal type.

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

From: Robert A. Duff
Sent: Thursday, November 11, 2004  3:34 PM

> Here's an AI writeup on the aggregates of partial views idea. We can discuss
> it as a "hole-filling" idea. Comments welcome.

Looks good to me.

> [Author's Note: This is needed so that an others choice for a partial view
> can match a null record full type. This is required so that we don't "leak"
> information about the full type to the uses. I believe that this is really a
> bug in AI-287 anyway; a default-initializing others should be allowed to
> match
> nothing, as it is harmless (by using OTHERS you've turned off completeness
> checking anyway) and useful.]

I understand why it's useful *here*, but why is it useful with just the
AI-287 change?

> If the aggregate denotes a partial view of a type, then the aggregate shall
> include OTHERS => <>.

I don't think you mean "denotes" here.  Aggregates don't denote types.
How about, "If the type of the aggregate is a partial..."

Some of the wording says "without an expression".  Does that mean "with
a box"?  And wouldn't the latter be clearer?

I agree with Pascal that we need to do likewise for generic formal
private types.  But I agree with Randy that that's not a problem.

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

From: Randy Brukardt
Sent: Thursday, November 11, 2004  4:57 PM

> > [Author's Note: This is needed so that an others choice for a partial view
> > can match a null record full type. This is required so that we don't "leak"
> > information about the full type to the uses. I believe that this is really a
> > bug in AI-287 anyway; a default-initializing others should be allowed to match
> > nothing, as it is harmless (by using OTHERS you've turned off completeness
> > checking anyway) and useful.]
>
> I understand why it's useful *here*, but why is it useful with just the
> AI-287 change?

Because it lets you have the inverse of the completeness check when that's
appropriate. That is, the aggregate won't need to be changed even in the
face of added or deleted components, so long as the ones that you care about
aren't changed.

It's a minor need, for sure, but I mentioned it to explain why I made the
rule apply always, and not just for aggregates of partial views.

> > If the aggregate denotes a partial view of a type, then the aggregate shall
> > include OTHERS => <>.
>
> I don't think you mean "denotes" here.  Aggregates don't denote types.
> How about, "If the type of the aggregate is a partial..."

Yeah, you're probably right here. Wrote this too fast...

> Some of the wording says "without an expression".  Does that mean "with
> a box"?  And wouldn't the latter be clearer?

I suppose; none of the existing wording ever says anything like "with a <>",
and I was trying to stay within the syntax.

> I agree with Pascal that we need to do likewise for generic formal
> private types.  But I agree with Randy that that's not a problem.

I was presuming that formal types were covered. If not, then we have nasty
wording, because you have to include not only formal private types but also
formal derived types whose ancestor is composite. Adding all of that to all
of the rules bloats things up a lot. That is,
"partial view of a type, a generic formal private type, or a generic formal
derived type whose ancestor is a composite type".

Yuck. I suppose we could try to give a name to that, but its a mixture of
views and types. Or maybe put that into a header and make the legality rules
bullets.

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

From: Editor

This AI was voted No-Action in Paris, after the complexities got out of
hand. There were a number of useful AARM notes explaining the rules in this
AI. I've copied them here to save them for posterity (especially if this
idea is resurrected in the future).

Add after 4.3.1(17):

17.2/2{AI95-00389-01} If the type of the record_aggregate is a partial
view of a type, a task type, a protected type, a formal private type, or a
formal derived type:

17.3/2{AI95-00389-01} The record_component_association_list shall include
others => <>; and

17.c/2Reason: For partial views and generic formals, this is needed to avoid
      "leaking" information about the full type to the aggregate. Without this
      rule, if the full type was null record, null record could be used; and if
      the full type had only one component, others => <some-expression> could
      be used. That would clearly break privacy. Similar issues apply to formal
      types; if information about the actual type could be used in the
      aggregate, we'd have a generic contract issue. Since each component can
      only occur in a single association, this rule prevents those issues.

17.d/2For tasks and protected types, this recognizes that there may be
      components (such as the lock for a protected type) that are known only to
      the implementation; these components necessarily have to be given default
      initialization. For portability, we don't want aggregates to be written
      that depend on whether the implementation has such components.

17.4/2{AI95-00389-01} The type of the record_aggregate shall have known
discriminants or be a tagged, task, or protected type that does not have
unknown discriminants; and

17.e/2Reason: We only want to allow aggregates of partial views when the full
      type is certain to be composite. Otherwise, we would have anomalies where
      additional visibility would cause the ability to have aggregates to
      disappear (if the full type is elementary). The full type is certain to
      be composite if the partial view has known discriminants or is tagged.
      Task and protected types are also allowed, as they are always composite.

17.f/2We also disallow types with unknown discriminants. Unknown discriminants
      are often used to prevent uncontrolled initialization of objects, and we
      don't want to provide an uncontrolled initialization mechanism for such
      types. Moreover, we would have break privacy to make them work. For
      instance:

17.g/2package P is
         type T (<>) is tagged private;
      private
         type T (D : Natural) is tagged record
            C : String (1..D);
         end record;
      end P;

17.h/2We couldn't allow giving an aggregate for T outside of P, because we
      don't know what value to give the discriminant D. But that would require
      looking in the private part to see if D had a default. It's better to
      disallow unknown discriminants generally.

17.5/2{AI95-00389-01} The record_component_association_list shall not include a
positional component association.

17.i/2Reason: Otherwise, positional notation could be used to give associations
      for components of the full view that are not visible to the aggregate.
      That would be bad. We disallow positional notation completely to avoid
      confusion and complexity; this shouldn't be a hardship since typically
      there will be no more than a couple discriminants along with others => <>
      in such an aggregate.

Replace 4.3.2(5) by:

5/2     {AI95-00306-01} {AI95-00389-01} If the ancestor_part is a subtype_mark,
it shall denote a specific tagged subtype. The type of the extension_aggregate
shall be a descendant of derived from the type of the ancestor_part, through
one or more record extensions (and no private extensions). If the ancestor_part
is an expression, it shall not be dynamically tagged. If the type of the
extension_aggregate is derived from the type of the ancestor_part through one
or more private extensions, then the record_component_association_list shall
include others => <>, and shall not include a positional component association.

5.a/2Reason: {AI95-00306-01} The expression cannot be dynamically tagged to
     prevent implicit "truncation" of a dynamically-tagged value to the
     specific ancestor type. This is similar to the rules in 3.9.2.

5.b/2{AI95-00389-01} We allow the type of the ancestor_part to be the type
     itself, so that these aggregates are allowed for generic formal derived
     types, where the actual type might be the same as the ancestor type.

5.c/2{AI95-00389-01} If the type involves any private extensions, we require
     the use of others => <> and disallow positional associations in order to
     avoid breaking privacy of the extensions. See 4.3.1 for a more complete
     discussion.

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


Questions? Ask the ACAA Technical Agent