Version 1.4 of ai12s/ai12-0409-1.txt

Unformatted version of ai12s/ai12-0409-1.txt version 1.4
Other versions for file ai12s/ai12-0409-1.txt

!standard 10.2.1(4.1/2)          20-12-15 AI12-0409-1/03
!standard 10.2.1(4.2/2)
!standard 10.2.1(11.1/2)
!standard 10.2.1(11.2/2)
!standard 10.2.1(11.6/2)
!standard 10.2.1(11.7/2)
!standard 10.2.1(11.8/2)
!standard 13.1(11/3)
!standard J.15.14(0)
!standard A.18.19(5/5)
!standard A.18.20(5/5)
!standard A.18.21(5/5)
!standard A.18.22(5/5)
!standard A.18.23(5/5)
!standard A.18.24(5/5)
!standard A.18.25(5/5)
!standard A.18.32(6/5)
!class Binding Interpretation 20-12-09
!status Amendment 1-2012 20-12-11
!status ARG Approved 11-0-3 20-12-09
!status work item 20-12-03
!status received 20-11-27
!priority Medium
!difficulty Easy
!qualifier Error
!subject Preelaborable_Initialization aspect and bounded containers
!summary
We define Preelaborable_Initialization to be an aspect, and allow for the situation where the full view is defined by the language or inheritance to be True, while the partial view is False.
We also define a Preelaborable_Initialization attribute, which is defined only for composite types defined in the visible part of a package or a generic package, and allow the aspect definition for a nonformal type declared within a generic package to depend on the value of such an attribute.
!problem
[A] Preelaborable_Initialization is one of the few remaining pragmas that cannot be specified using an aspect specification. The reason for this is a technicality (see AI05-0229-1):
===pragma Preelaborable_Initialization (referred to as P_I below)
[Editor's Note: This pragma does not work well as a type-related aspect, as it is view dependent. In particular, even if a partial view does not have the P_I property, the full view might have the P_I property. That is contrary to 13.1(11/2) for operational and representation aspects. (In the absence of a change to 13.1(11/2), we'd have a compatibility problem.) ...]
---
This seems like it could be fixed, and it is a bit of an anomaly. I believe the goal was that it was OK if the partial view did not have the aspect visibly True, since you might change the implementation at some point to not have preelaborable initialization. On the other hand, for other aspects we are forcing you to reveal the full view's aspect in the partial view. Nonblocking is currently such an aspect, though we believe this should probably also be changed. There are two conceivable approaches, but only the second really works for Preelaborable_Initialization:
1) Force the partial view to match the full view, and say that it has Preelaborable_Initialization, even if at some later point you fear the implementation might no longer be able to meet that requirement -- alas this doesn't really work as it would require pragma Preelaborable_Initialization for all private types that turn out to have a full type with preelaborable initialization -- this would be quite incompatible with the current language;
2) Allow the partial view and the full view to have different values for certain Boolean-valued aspects, but probably limited to False for the partial view and True for the full view. We already have a rule analogous to this on inheritance of Boolean aspects, in RM 13.1.1(18.1/5):
If an aspect of a derived type (or its first subtype) is inherited from an ancestor (sub)type and has the boolean value True, the inherited value shall not be overridden to have the value False for the derived type (or its first subtype), unless otherwise specified in this International Standard. If an aspect of a nonfirst subtype is inherited from the subtype in the subtype_indication that defines it, and has the value True, the inherited value shall not be overridden to have the value False for the nonfirst subtype, unless otherwise specified in this International Standard.
We do allow aspects to be completely unspecified on a partial view, while being specified on the full view (RM 13.1.1(35/3)). So this could be seen as a variant of that for Boolean aspects for which "False" is the default value if not specified.
===
[B] Is it intended that a bounded container has Preelaborable_Initialization even if the actual Element_Type does not have Preelaborable_Initialization? That seems to make it impossible to store the elements directly in the container, and seems to require some sort of dynamic memory allocation (contrary to the Implementation Advice).
!proposal
[A] Modify the general rule about partial view and full view having the same value for all aspects, to allow an exception for certain boolean-valued aspects, where the partial view may be False while the full view is True. We would use this at least for Preelaborable_Initialization where we would allow the full type to be "better behaved" than the partial view.
[B] A bounded container should have Preelaborable_Initialization only if the actual Element_Type (and Key_Type for Maps) has Preelaborable_Initialization. We introduce a Preelaborable_Initialization attribute for formal composite types, and allow it to be used in the definition for the Preelaborable_Initialization aspect of a non-formal type defined within a generic.
!wording
[Author's note: This is defined as modifications to the wording introduced by AI12-0399-1.]
Move 10.2.1(4.1/2, 4.2/2) defining the pragma Preelaborable_Initialization to Annex J, as section J.15.14.
Modify 10.2.1(11.1/2):
The following rules specify which entities have preelaborable initialization {, namely that the Preelaborable_Initialization aspect of the entity is True}.
Modify 10.2.1(11.2/3):
The partial view of a private type or private extension, a protected type without entry_declarations, a generic formal private type, or a generic formal derived type, has preelaborable initialization if and only if the [pragma] Preelaborable_Initialization {aspect} has been [applied to]{specified True for} them. [Redundant: A protected type with entry_declarations or a task type never has preelaborable initialization.] {The Preelaborable_Initialization aspect of a partial view of a type may be specified as False, even if the full view of the type has preelaborable initialization. Similarly, a generic formal type need hot be specified to have preelaborable initialization, even if the actual type in an instance has preelaborable initialization.}
In place of 10.2.1(11.6/2), which is moved to Annex J with modifications (see below), add the following:
The following attribute is defined for a nonformal composite subtype S declared within the visible part of a package or a generic package, or a generic formal private subtype or formal derived subtype.
S'Preelaborable_Initialization
This attribute is of Boolean type, and its value reflects whether the type of S has preelaborable initialization. The value of this attribute, the type-related Preelaborable_Initialization aspect, may be specified for any type for which the attribute is defined. The value shall be specified by a static expression, unless the type is not a formal type but is nevertheless declared within a generic package. In this latter case, the value may also be specified by references to the Preelaborable_Initialization attribute of one or more formal types visible at the point of the declaration of the composite type, conjoined with "and".
Modify 10.2.1(11.7/3):
[If the pragma appears in the first list of basic_declarative_items of a package_specification, then the direct_name shall denote the first subtype of a composite type, and the type shall be declared immediately within the same package as the pragma.] If the [pragma is applied to]{Preelaborable_Initialization aspect is specified True for} a private type or a private extension, the full view of the type shall have preelaborable initialization. If the [pragma is applied to]{aspect is specified True for} for a protected type, the protected type shall not have entries, and each component of the protected type shall have preelaborable initialization. {If the aspect is specified True for a generic formal type, then in a generic_instantiation the corresponding actual type shall have preelaborable initialization. If the aspect is specified to be the conjunction of one or more Preelaborable_Initialization attribute references, then the full view of the type shall have preelaborable initialization presuming the types mentioned in the conjunction all have preelaborable initialization.} For any other composite type, the [type shall have preelaborable initialization]{aspect shall be specified statically True or False only if it is confirming}. In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit.
Modify 10.2.1(11.c/3):
AARM Reason: {AI05-0028-1} The reason why we need [the pragma]{to specify the aspect} for private types, private extensions, and protected types is fairly clear: the properties of the full view determine whether the type has preelaborable initialization or not; in order to preserve privacy we need a way to express on the partial view that the full view is well-behaved. The reason why we need [the pragma]{to specify the aspect} for other composite types is more subtle: a nonnull override for Initialize might occur in the private part, even for a nonprivate type; in order to preserve privacy, we need a way to express on a type declared in a visible part that the private part does not contain any nasty override of Initialize.
Delete 10.2.1(11.8/2), which is now covered above. For reference, this paragraph was:
If the pragma appears in a generic_formal_part, then the direct_name shall denote a generic formal private type or a generic formal derived type declared in the same generic_formal_part as the pragma. In a generic_instantiation the corresponding actual type shall have preelaborable initialization.
Modify 10.2.1(11.d/2):
AARM Ramification: Not only do protected types with entry_declarations and task types not have preelaborable initialization, but they cannot have [pragma]{the aspect} Preelaborable_Initialization [applied to]{specified True for} them.
Modify 13.1(11/3) -- as defined in AI12-0396-1:
If a type-related aspect is defined for the partial view of a type, then it has the same definition for the full view of the type{, except for certain Boolean-valued operational aspects where the language specifies that the partial view can have the value False even when the full view has the value True}. ...
{AARM Discussion: This applies to aspect Preelaborable_Initialization. Nonblocking has a similar rule, though it is a subtype-specific aspect.}
Add after A.18.19(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add after A.18.20(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add after A.18.21(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization and Key_Type'Preelaborable_Initialization
Add after A.18.22(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization and Key_Type'Preelaborable_Initialization
Add after A.18.23(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add after A.18.24(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add after A.18.25(5/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add after A.18.32(6/5):
* the aspect_definition for Preelaborable_Initialization is changed to:
Preelaborable_Initialization =>
Element_Type'Preelaborable_Initialization
Add the following section to Annex J:
J.15.14 Pragma Preelaborable_Initialization:
Syntax
The form of a pragma Preelaborable_Initialization is as follows:
pragma Preelaborable_Initialization(direct_name);
Legality Rules
A pragma Preelaborable_Initialization specifies that the Preelaborable_Initialization aspect (see 10.2.1) for a composite type is True. This pragma shall appear in the visible part of a package or generic package.
If the pragma appears in the first list of basic_declarative_items of a package_specification, then the direct_name shall denote the first subtype of a composite type, and the type shall be declared immediately within the same package as the pragma. The composite type shall be one for which the Preelaborable_Initialization aspect can be directly specified as True. In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit.
If the pragma appears in a generic_formal_part, then the direct_name shall denote a type declared in the same generic_formal_part as the pragma, and be one for which the Preelaborable_Initialization aspect can be directly specified as True.
!discussion
(1) It is an anomaly that Preelaborable_Initialization is the only "characteristic" of a type that is not considered an aspect. The reason we had deferred making this an aspect had to do with the now-altered rule that all views of a type would have the same value for all aspects. We now limit that rule to representation aspects. For operational aspects, we recognize that there are reasons why the partial view might want to be different, especially if the full view has a language-defined value for the aspect, which is true for both Preelaborable_Initializaation for certain simple types and for Nonblocking for base subtypes of elementary types. It is awkward for the partial view to be required to reveal this property of the full type, and it would be incompatible to do so for Preelaborable_Initialization, and for Nonblocking, as suddenly various private types would be required to have these aspects explicitly specified.
Therefore, we recognize these special cases, where the default value of False generally imposes no special requirement, while the value of True does impose requirements on the type and some of its operations. For such cases we permit the value for the full type to be True, even if the partial view makes no such "promise" by having the value False for the aspect.
We move the pragma to the Obsolescent Annex (Annex J), to be consistent with our handling of other similar pragmas.
(2) We debated various ways to address this issue. Although we have abandoned the use of attributes for Nonblocking and Global, we felt that for this particular aspect, allowing the use of an attribute was the simplest solution. We considered defining some additional aspect, or making some automatic rule, but none of them seemed as simple as this approach, which seemed both intuitive and readable.
!examples
See the updates to A.18.19-25 above.
!ASIS
[Not sure. Probably the attribute needs to be added to some enumeration, but I didn't check - Editor.]
!ACATS test
ACATS B- and C-Tests are needed to check that the new capabilities are supported.
We do not want any Ada 2012 tests that require any form of the Preelaborable_Initialization aspect to be supported. We also do not want any Ada 2012 tests that insist that a bounded container type does not have preelaborable initialization for an element type that does not have preelaborable initialization. This is a Binding Interpretation so that it can be supported for Ada 2012 compilers, and so that an Ada 2012 compiler can write a legal body for a bounded container in Ada. (If the Ada 2012 has some other method to make bounded containers legal, we do not want to require them to change it.)
!appendix

!topic Bounded containers cannot be implemented in Ada
!reference Ada 2012 RM 10.2.1 A.18.19-25
!from Jeff Carter
!discussion

I posted to comp.lang.ada:

CLA_Quote : begin

Consider the package

with Ada.Containers.Bounded_Doubly_Linked_Lists;

generic
   type E is private;
package Preelaborable is
   package EL is new Ada.Containers.Bounded_Doubly_Linked_Lists
      (Element_Type => E);
end Preelaborable;

Two Ada-12 compilers give different results on this. Compiler G accepts it 
without problem. Compiler O rejects it with the error message

preelaborable.ads: Error: line 6 col82 LRM:10.2.1(11.8/2), If a pragma 
Preelaborable_Initialization has been applied to the generic formal, the 
corresponding actual type must have preelaborable initialization

AFAICT from the ARM, the generic formal Element_Type of 
Ada.Containers.Bounded_Doubly_Linked_Lists does not have pragma 
Preelaborable_Initialization applied to it. However, the type List, which 
probably has [sub]components of Element_Type, does.

Which compiler is correct? What is the intent of the ARM?

end CLA_Quote; 
to which Randy Brukardt responded

RB_Quote : begin

I'd say both compilers are wrong, in that the RM clearly has a bug here and 
one of the implementers should have complained about it to the ARG long ago. 
:-) I'd suggest you post this question to Ada-Comment so that it gets on the 
ARG's radar.

(I'll call Preelaborable_Initialization "PI" in the following for my sanity. 
:-)

It's clear from 10.2.1 that a type with pragma PI which has components of a 
generic formal type has to have components that have a type with PI. It 
isn't possible to initialize such components without a function call, so the 
other possibility does not exist. The Bounded containers are designed such 
that there are components of the element type (more accurately, a component 
of an array of the element type). In order for there to be such a component, 
the formal type must have PI. Ergo, any body for a bounded container written 
in Ada is necessarily illegal. This is a problem that someone should have 
brought up at the ARG.

Since it is not required to write language-defined package bodies in Ada, 
one could imagine that both compilers are correct in the sense that they are 
using some non-Ada language to implement the containers. But that is is a 
fiction in the case of the containers (every implementation I know of is in 
Ada), and in any case, we intended the containers to be implementable in 
Ada. If they are not, that is a bug.

I don't know what the fix ought to be: adding PI to the formal private type 
would work, but it would reduce the usabibility of the containers in 
non-preelaborated contexts. Similarly, removing the PI from the container 
would work, but would reduce the usability of the containers in 
preelaborated contexts. Both seem pretty bad.

I'd be in favor of removing PI and Preelaboration in general from the 
language (it serves no purpose other than to encourage implementers to make 
optimizations that they should make anyway - the other intentions don't work 
or are better handled with other mechanisms), but I doubt that I'd get any 
support for that.

end RB_Quote;

My initial thought when encountering this was that leaving PI on the container 
was an oversight. 

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

From: Tucker Taft
Sent: Friday, November 27, 2020  7:50 AM

One reasonable interpretation is that the lists should have preelaborable 
initialization if and only if the element type has P.I.  I don't know how to 
express this in existing Ada, but that seems like the best answer and could be 
described in English, with some future pragma used to enforce it.

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

From: Tucker Taft
Sent: Friday, November 27, 2020  8:32 AM

I suppose one could implement this as follows, even if Element_Type did *not* 
have preelaborable initialization:

    type Element_Array is array (Count_Type range <>) of Element_Type;

    type Inner_List (Capacity : Count_Type := 0) is record
         Data : Element_Array (Capacity);
   end record;

    type List (Capacity : Count_Type) is tagged record
         Length : Count_Type := 0;
         Inner : Inner_List;  --  Defaults to Capacity = 0
    end record;

And then the first update to such a list which added any elements could do a 
full-object assignment to "Inner":

     procedure Append (Container : in out List; New_Item : Element_Type) is
     begin
         if Container.Inner.Capacity = 0 then
               --  Initialize the inner object by full-record assignment
               Container.Inner := (Capacity => Container.Capacity, Data => (others => <>));
         end if;
         pragma Assert (Container.Inner.Capacity = Container.Capacity);
         ...
    end Append;

This means that there are no subcomponents of type Element_Type in a 
default-initialized object of type List, so it doesn't matter whether 
Element_Type has preelaborable initialization.

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

From: Randy Brukardt
Sent: Friday, November 27, 2020  9:38 PM

I don't think this works, at least not without a lot of language and compiler 
surgery:

First of all, PI requires that all of the subcomponents are either 
default-initialized or have a type with PI. Neither of these are true for your 
Inner_List type. Moreover, there's nothing in the PI rules allowing one to 
ignore "discriminant-dependent components" in any case. Since a compiler will
presumably need to use special code generation for types with PI (at least to
avoid some possibilities), it seems that it would be very painful to support 
such a cut-out.

Secondly, most compilers use an allocate-the-max strategy for types with 
defaulted discriminants. Since Count_Type is typically implemented to put the 
minimal limits on containers, Count_Type'Last is usually at least 2**32.
As such, any object of type Inner_List is going to use a massive amount of 
memory. You want to have the (outer) object's discriminant determine the 
amount of memory to allocate, not some later dynamically determined 
discriminant.

An implementation that uses some form of dynamic allocation for types like 
Inner_List (those with defaulted discriminants) could use this format, but 
that would completely defeat the purpose of the bounded containers in 
avoiding dynamic allocation.

So I don't think this way leads anywhere.

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

From: Tucker Taft
Sent: Friday, November 27, 2020  10:55 AM

> First of all, PI requires that all of the subcomponents are either 
> default-initialized or have a type with PI. Neither of these are true 
> for your Inner_List type. Moreover, there's nothing in the PI rules 
> allowing one to ignore "discriminant-dependent components" in any 
> case. Since a compiler will presumably need to use special code 
> generation for types with PI (at least to avoid some possibilities), 
> it seems that it would be very painful to support such a cut-out.

I think this could be fixed with:

     type List (Capacity : Count_Type) is tagged record
        Length : Count_Type := 0;
        Inner : Inner_List := (Capacity => 0, Data => (others => <>));
    end record;

> Secondly, most compilers use an allocate-the-max strategy for types 
> with defaulted discriminants. Since Count_Type is typically 
> implemented to put the minimal limits on containers, Count_Type'Last is
> usually at least 2**32.
> As such, any object of type Inner_List is going to use a massive 
> amount of memory. You want to have the (outer) object's discriminant 
> determine the amount of memory to allocate, not some later dynamically 
> determined discriminant.

Presumably we could pick some reasonable upper bound.

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

From: Randy Brukardt
Sent: Saturday, November 28, 2020  8:10 PM

> Presumably we could pick some reasonable upper bound.

I don't see how. Element sizes can vary wildly (from a single pointer to 
an array of thousands of records). There would either be massive amounts of
waste (beyond that already implied by the design of the bounded container),
or the limit would be too small for some uses (thousands of elements can 
occur in some containers).

Arbitrary limits are always a problem, sooner or later.

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

From: Tucker Taft
Sent: Saturday, November 28, 2020  8:54 PM

Agreed.  Not really a solution -- it was more of an exercise.

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

From: Randy Brukardt
Sent: Friday, November 27, 2020  9:57 PM

> One reasonable interpretation is that the lists should have 
> preelaborable initialization if and only if the element type has P.I.

That would be a reasonable goal, but that's not what the language currently 
says.

It certainly would make sense for most generics to work this way, since it 
doesn't make a lot of sense to declare objects to have PI if they have parts
that don't have PI.

> I don't know how to express this in existing Ada, but that seems like 
> the best answer and could be described in English, with some future 
> pragma used to enforce it.

I don't think we should start trying to describe basic functionality in 
English -- it's the wrong direction.

I think it would make the most sense to define a new aspect related to 
Preelaborable_Initialization for this case. Brainstorming on this a bit, I 
think we might want to use the Use_Formal mechanism along with this.

So, presenting a barely-thought-out proposal:

For a type for which aspect Preelaborable_Initialization can be specified and 
which is declared in a generic specification, the following aspect can be 
specified:

   Generic_Preelaborable_Initialization  The type of this aspect is Boolean 
   and shall be specified with a static expression.

   When True, enforces preelaborable initialization restrictions on the 
   associated type has preelaborable initialization assuming that all formal
   types of the generic unit (or those given in an Use_Formal clause on the 
   same type declaration) have preelaborable initialization.

   When True, in an instance, the associated type has preelaborable 
   initialization if and only all of the actual types for the formal types 
   of the generic unit (or those given in an Use_Formal clause on the same 
   type declaration) have preelaborable initialization.

   When False, the type does not have preelaborable initialization.

---

An alternative would be to revise the existing (but just added) 
Preelaborable_Initialization aspect to work this way; that would requiring 
adding Use_Formal => null to existing predefined preelaborated generic units 
other than the bounded containers. (Note that the unbounded and indefinite 
containers do not have this problem, as the elements aren't allocated until
they are inserted.) I'm a bit concerned that people might change pragma PI 
into aspect PI without noting this difference. It would reduce the amount of
complication, but I worry that the case where the private type in the generic
unit doesn't have any parts of the formal types (or at least any parts that 
need PI) is too common to require a two-part declaration for it.

---

A different alternative would be to have the aspect take a list of formal 
types rather than using the Use_Formal mechanism. That seems more complex 
to define, since we'd have to invent some list syntax and add a bunch of 
rules about the resolution of them. Use_Formal already does this, and I'd 
think that much of the time, you would want all (or none) of the formal types
involved anyway.

---

Thoughts???

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

From: Tucker Taft
Sent: Saturday, November 28, 2020  7:30 AM

My goal would be to keep things as simple as possible, but still solve this
problem. ;-)

If we believe the only problem is the bounded containers, then it would be 
nice if the solution only required a change to them.  On the other hand, if 
you go to the trouble of specifying an aspect with a name as long as 
"Preelaborable_initialization" then perhaps expecting a bit more is not 
unreasonable.

Unfortunately, Use_Formal is an Annex H feature, and is clearly oriented 
toward Global and Nonblocking, so allowing its use for 
Preelaborable_Initialization is bound to add complexity, since that aspect 
is in the "core" of the standard.

An alternative not mentioned was to define an attribute 
'Preelaborable_Initialization, and allow the specification of the 
Preelaborable_Initialization aspect of a type declared within a generic to 
refer to the Preelaborable_Initialization of a generic formal type.  We have 
had trouble with this in the past for the use of 'Nonblocking and 'Global, but
this seems like a simpler situation.

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

From: Randy Brukardt
Sent: Saturday, November 28, 2020  8:03 PM

...
> An alternative not mentioned was to define an attribute 
> 'Preelaborable_Initialization, and allow the specification of the 
> Preelaborable_Initialization aspect of a type declared within a 
> generic to refer to the Preelaborable_Initialization of a generic 
> formal type.  We have had trouble with this in the past for the use of 
> 'Nonblocking and 'Global, but this seems like a simpler situation.

I rejected that solution simply because it was rejected for Nonblocking. And 
there the problem was mainly with the rules for nested generics (which meant 
that the aspect was no longer a simple Boolean aspect, but rather was based 
on expressions). We'd still have that sort of issue here.

I'd rather have a general solution if at all possible, because users ought to 
be able to write their own containers. The less "magic" we have to use the 
better. And we spent quite a bit of effort on formal incomplete types, 
generalized indexing, and generalized references just to avoid using magic
in the containers -- it would be sad to introduce some at this late point 
(and with something that's quite a bit easier).

I suppose we could split the baby and not worry about cases where more than 
one generic formal is involved (we don't need that for the bounded containers;
it's just bad language design to only allow one of something, but some iffy 
design is OK if we don't expect this to be used much outside of the 
containers). That would simplify the definition of the 
Generic_Preelaborable_Initialization aspect to be a single name that has to be 
of a formal type of an enclosing generic unit.

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

From: Tucker Taft
Sent: Saturday, November 28, 2020  8:53 PM

> ...
>> An alternative not mentioned was to define an attribute 
>> 'Preelaborable_Initialization, and allow the specification of the 
>> Preelaborable_Initialization aspect of a type declared within a 
>> generic to refer to the Preelaborable_Initialization of a generic 
>> formal type.  We have had trouble with this in the past for the use 
>> of 'Nonblocking and 'Global, but this seems like a simpler situation.
> 
> I rejected that solution simply because it was rejected for 
> Nonblocking. And there the problem was mainly with the rules for 
> nested generics (which meant that the aspect was no longer a simple 
> Boolean aspect, but rather was based on expressions). We'd still have that
> sort of issue here.

Could you give an example?  My hope was that it wouldn't suffer from the 
complexity of 'Nonblocking.

> I'd rather have a general solution if at all possible, because users 
> ought to be able to write their own containers. The less "magic" we 
> have to use the better. And we spent quite a bit of effort on formal 
> incomplete types, generalized indexing, and generalized references 
> just to avoid using magic in the containers -- it would be sad to 
> introduce some at this late point (and with something that's quite a bit easier).

I agree we don't want a "magic" solution -- I don't think the 
'Preelaborable_Initialization attribute is magic.  Which of the solutions we 
discussed uses "magic"?
 
> I suppose we could split the baby and not worry about cases where more 
> than one generic formal is involved (we don't need that for the 
> bounded containers; it's just bad language design to only allow one of 
> something, but some iffy design is OK if we don't expect this to be 
> used much outside of the containers). That would simplify the 
> definition of the Generic_Preelaborable_Initialization aspect to be a 
> single name that has to be of a formal type of an enclosing generic unit.

I would rather not introduce another aspect if we can avoid it.

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

From: Randy Brukardt
Sent: Sunday, November 29, 2020  1:17 AM

> > I rejected that solution simply because it was rejected for 
> > Nonblocking. And there the problem was mainly with the rules for 
> > nested generics (which meant that the aspect was no longer a simple 
> > Boolean aspect, but rather was based on expressions). We'd still 
> > have that sort of issue here.
> 
> Could you give an example?  My hope was that it wouldn't suffer from 
> the complexity of 'Nonblocking.

It would, because the aspect would have to be an expression, rather than a 
Boolean value. Inside of a generic, one does not have a known value for 
<Formal_Type>'Preelaborable_Initialization. So that would mean that one would
need all of the handwaving about expressions that evaluate to a static value 
that was the real problem with 'Nonblocking. (Yes, the rules in the generic 
body were fairly complex, but they did the right thing -- no one would have 
to understand them. The stuff about static expressions and nonstatic 
expressions was pervasive -- when you changed back to a pure Boolean model 
you changed 50% of the wording -- and most of what you didn't change probably
should have been changed too.) If you tried to avoid that handwaving, it 
wouldn't be possible to make the needed P_I checks (or more accurately, *not*
make the checks in specific cases).

I can give some examples on Monday; it's too late tonight (time to go home - 
I've been Christmas shopping [on-line] tonight).

> I would rather not introduce another aspect if we can avoid it.

Trying to use one aspect would be way more complex than using two with 
targetted rules. The only way to do that makes sense to me would be piggyback 
on Use_Formal, which you said you didn't want to do.

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

From: Tucker Taft
Sent: Monday, November 30, 2020  9:26 AM

> It would, because the aspect would have to be an expression, rather than a
> Boolean value. Inside of a generic, one does not have a known value for
> <Formal_Type>'Preelaborable_Initialization. So that would mean that one
> would need all of the handwaving about expressions that evaluate to a static
> value that was the real problem with 'Nonblocking. (Yes, the rules in the
> generic body were fairly complex, but they did the right thing -- no one
> would have to understand them. The stuff about static expressions and
> nonstatic expressions was pervasive -- when you changed back to a pure
> Boolean model you changed 50% of the wording -- and most of what you didn't
> change probably should have been changed too.) If you tried to avoid that
> handwaving, it wouldn't be possible to make the needed P_I checks (or more
> accurately, *not* make the checks in specific cases).

I think it is a bit simpler because P_I is only permitted on composite types, 
and the attribute would only be defined on formal private types/extensions.  
Therefore we could restrict the definition of the P_I aspect to either False, 
True, or "formal'P_I and formal'P_I and formal'P_I and ...".  Nothing more 
complex than that would be needed, I believe.

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

From: Randy Brukardt
Sent: Tuesday, December 1, 2020  12:17 AM

Sure, but the expensive part is changing the aspect from a static Boolean 
value to something else to allow the expression (whatever form it would have).
As I noted yesterday, we'd have to change just about every reference to the 
aspect in the RM text, as it would have to be an expression-valued aspect. 
And then there would have to be the nasty hand-waving about when the 
expression has a static value. (At least if we followed the old model of 
Nonblocking. That was never very satisfactory.)

The complications to the P_I rules themselves is not a real concern here -- 
especially as we could simply treat any named formal types as if they have 
P_I. It's the changes needed to support an expression-valued aspect when one
cannot assume that you have a static expression.

BTW, one has to support static boolean expressions, not just the literals True
and False. There are a number of plausable uses for a global Boolean constant 
rather than using a literal. (Presumably, one would use the constant both for 
the package Preelaborate and any Preelaborable_Initializations.) It would be 
nasty to be able to use a named constant for Preelaborate but not be able to 
do that for Preelaborable_Initialization.

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

From: Tucker Taft
Sent: Tuesday, December 1, 2020  6:58 AM

Unlike "nonblocking," the term "preelaborable initialization" appears 
extremely rarely in the normative wording of the reference manual.  In 
particular, I believe that it appears in exactly three places -- 10.2.1,
13.7, and the index.  Of course an aspect definition for 
Preelaborable_Initialization appears in many places, but that seems irrelevant 
to this situation.  We will only be changing that for bounded containers, and 
we have to make some change for bounded containers if we are going to fix this
problem.

I would suggest that I write up an AI with the wording changes for this 
approach, and see how bad it looks.

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

From: Randy Brukardt
Sent: Thursday, December 3, 2020  9:40 PM

[This is relative to draft /01 of the AI - Editor.]

I had a number of comments on the draft of AI12-0409-1 that will be on the 
agenda; since Tucker does not plan to address any of them before the agenda 
is posted I'm putting them here for the record (so we can discuss them at the
meeting or here). The full AI will go up with the agenda tonight.

---

!wording
> [Author's note: This is defined as modifications to the wording 
> introduced by AI12-0399-1.]

It's rather hard to evaluate this wording without the other wording (which 
will not be in draft 27, either, as I didn't want to do all of that work 
twice).

Note that AI12-0399-1 is an Amendment, so an AI modifying it cannot be a 
Binding Interpretation. Since this problem really needs a fix for Ada 2012, we 
probably need to move the aspect wording from that AI to this one (leaving the 
library changes from pragma to aspect).

> In place of 10.2.1(11.6/2), which was moved to Annex J, add the
> following:
> 
>   The following attribute is defined for a nonformal composite subtype S
>   declared within the visible part of a package or a generic package, or
>   a generic formal private subtype or formal derived subtype.
> 
>   S'Preelaborable_Initialization
>   
>     This attribute is of Boolean type, and its value reflects whether
>     the type of S has preelaborable initialization. The value of this
>     attribute, the type-related Preelaborable_Initialization aspect, may
>     be specified for any type for which the attribute is defined. The
>     value shall be specified by a static expression, unless the type is
>     not a formal type but is nevertheless declared within a generic
>     package.  In this latter case, the value may also be specified by
>     references to the Preelaborable_Initialization attribute of one or
>     more formal types visible at the point of the declaration of the
>     composite type, conjoined with "and".

(1) Do we really want to introduce a new specifiable attribute (which implies 
that attribute_definition_clauses need to be supported)? Nonblocking defined 
attributes, but only allow specification of aspects.

(2) Why the restriction to "not a formal type"? It seems like a nested generic 
of a type similar to the containers might need to depend on an outer formal 
type. Perhaps this is OK if we agree that this is a hack rather than a 
well-defined feature. (The same goes for the inability to combine a static
expression with some aspects.)

(3) Does this work right if a generic used in a formal package uses this 
aspect? Shouldn't it be possible to depend on the P_I attribute of (some 
formal type of) a formal package parameter?

> Modify 10.2.1(11.7/3):
> 
>   [The Preelaborable_Initialization aspect shall be directly specified
>   only for a composite type declared within the visible part of a
>   package or a generic package.  ]If the Preelaborable_Initialization
>   aspect is specified True for a private type or a private extension,
>   the full view of the type shall have preelaborable initialization. If
>   the aspect is specified True for a protected type, the protected type
>   shall not have entries, and each component of the protected type shall
>   have preelaborable initialization. {If the aspect is specified True
>   for a generic formal type, then in a generic_instantiation the
>   corresponding actual type shall have preelaborable initialization. If
>   the aspect is specified to be the conjunction of one or more
>   Preelaborable_Initialization attribute references, then the full view
>   of the type shall have preelaborable initialization presuming the
>   types mentioned in the conjunction all have preelaborable
>   initialization.} ...

We haven't used the word "conjunction" before in the Standard, just saying an 
"and" of things. Seems kinda late to introduce such a term.

Additionally, the phrase "the types mentioned in the conjunction" seems too 
handwavy to me. Something like "the types mentioned in the prefixes of the 
"and"ed Preelaborable_Initialization attribute references" would be clearer 
and avoid introducing the first use of conjunction in the Standard. 

>   ... For any other composite type, the aspect shall be
>   specified statically True or False only if it is confirming. In
>   addition to the places where Legality Rules normally apply (see 12.3),
>   these rules apply also in the private part of an instance of a generic
>   unit.

Is it clear from the other wording (which I don't have in front of me) that 
the *aspect* value is determined by whether or not a type is defined to have 
preelaborable initialization? I know that whether a type has preelaborable 
initialization is well defined for most types, but that doesn't say anything 
about the aspect value. I fear that the definition could very well be circular
(the aspect depends on whether the type has preelaborable initialization, and 
the type has preelaborable initialization if the aspect is True; if both of 
these things are defined, then it is impossible for the aspect to be 
confirming, as the specification of it has already changed the value).

---

How does this aspect relate to the rules for Boolean-valued aspects? In 
particular, if the value is not a statically known Boolean-value, how can one 
enforce 13.1.1(18.1/4)?? Are you assuming a re-check in specs? What about 
generic bodies?? (In case you missed what I'm driving at, you cannot know at 
generic unit compile-time what the value for the parent type is. So how do you 
know if the rule applies?)

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

From: Tucker Taft
Sent: Tuesday, December 8, 2020  9:22 PM

I have sent Randy some responses to these comments privately.  I'll discuss 
them during the meeting.  But in the mean time, it seemed like a lot of the 
difficulty in understanding this AI was the mixture of wording coming from 
the RM draft 27, AI12-0399-1, and this AI.  So I have combined all of the 
wording, deleted the parts that are going to be removed, shown the new parts
in {...}, and provided it below.  Hopefully this can be a better place to 
start our discussions on this AI.  I know Randy still has comments that apply
to this combined wording, but hopefully it will be easier for everyone if we 
aren't trying to on-the-fly patch the wording together in our heads.

> On Dec 3, 2020, at 10:39 PM, Randy Brukardt <Randy@RRSOFTWARE.COM> wrote:
> 
> I had a number of comments on the draft of AI12-0409-1 that will be on the
> agenda; since Tucker does not plan to address any of them before the agenda
> is posted I'm putting them here for the record (so we can discuss them at
> the meeting or here). The full AI will go up with the agenda tonight.
> 
> ---
> 
> ...

======== combined wording from RM, AI12-0399-1, and AI12-0409-1 =========

Here is a complete rewrite of the part of 10.2.1 that relates to preelaborable 
initialization, with the obsolete parts marked [...] in the AIs eliminated completely:

  An elaborable construct is preelaborable unless its elaboration
  performs any of the following actions:

  ...

  * The creation of an object [Redundant: (including a component)] that
    is initialized by default, if its type does not have preelaborable
    initialization. Similarly, the evaluation of an extension_aggregate
    with an ancestor subtype_mark denoting a subtype of such a type.

  * The elaboration of any elaborable construct that is not
    preelaborable.

  A generic declaration is preelaborable unless every instance would
  perform one of the above actions.

  A generic body is preelaborable only if elaboration of a corresponding
  instance body would not perform any such actions, presuming that:

  * the actual for each discriminated formal derived type, formal
    private type, or formal private extension declared within the formal
    part of the generic unit is a type that does not have preelaborable
    initialization, unless {the Preelaborable_Initialization aspect is
    specified True for} the formal type;

  * the actual for each formal type is nonstatic;

  * the actual for each formal object is nonstatic; and

  * the actual for each formal subprogram is a user-defined subprogram. 
 
  A pragma Preelaborate (or pragma Pure  see below) is used to specify
  that a library unit is preelaborated, namely that the Preelaborate
  aspect of the library unit is True; all compilation units of the
  library unit are preelaborated. The declaration and body of a
  preelaborated library unit, and all subunits that are elaborated as
  part of elaborating the library unit, shall be preelaborable. All
  compilation units of a preelaborated library unit shall depend
  semantically only on declared pure or preelaborated library_items. In
  addition to the places where Legality Rules normally apply (see 12.3),
  these rules also apply in the private part of an instance of a generic
  unit. [Redundant: If a library unit is preelaborated, then its
  declaration, if any, and body, if any, are elaborated prior to all
  nonpreelaborated library_items of the partition.]

  Subunits of a preelaborated subprogram unit do not need to be
  preelaborable. This is needed in order to be consistent with units
  nested in a subprogram body, which do not need to be preelaborable
  even if the subprogram is preelaborated. However, such subunits cannot
  depend semantically on nonpreelaborated units, which is also
  consistent with nested units.

  The following rules specify which entities have preelaborable
  initialization{, namely that the Preelaborable_Initialization aspect
  of the entity is True}:

  * The partial view of a private type or private extension, a protected
    type without entry_declarations, a generic formal private type, or a
    generic formal derived type, has preelaborable initialization if and
    only if the Preelaborable_Initialization {aspect} has been
    {specified True for} them. [Redundant: A protected type with
    entry_declarations or a task type never has preelaborable
    initialization.] {The Preelaborable_Initialization aspect of a
    partial view of a type may be specified as False, even if the full
    view of the type has preelaborable initialization. Similarly, a
    generic formal type need hot be specified to have preelaborable
    initialization, even if the actual type in an instance has
    preelaborable initialization.}

  * A component (including a discriminant) of a record or protected type
    has preelaborable initialization if its declaration includes a
    default_expression whose execution does not perform any actions
    prohibited in preelaborable constructs as described above, or if its
    declaration does not include a default expression and its type has
    preelaborable initialization.

  * A derived type has preelaborable initialization if its parent type
    has preelaborable initialization and if the noninherited components
    all have preelaborable initialization. However, a controlled type with
    an Initialize procedure that is not a null procedure does not have
    preelaborable initialization.

  * A view of a type has preelaborable initialization if it is an
    elementary type, an array type whose component type has preelaborable
    initialization, a record type whose components all have preelaborable
    initialization, or an interface type.
  
  {The following attribute is defined for a nonformal composite subtype S
  declared within the visible part of a package or a generic package, or
  a generic formal private subtype or formal derived subtype.

  S'Preelaborable_Initialization
  
    This attribute is of Boolean type, and its value reflects whether
    the type of S has preelaborable initialization. The value of this
    attribute, the type-related Preelaborable_Initialization aspect, may
    be specified for any type for which the attribute is defined. The
    value shall be specified by a static expression, unless the type is
    not a formal type but is nevertheless declared within a generic
    package.  In this latter case, the value may also be specified by
    references to the Preelaborable_Initialization attribute of one or
    more formal types visible at the point of the declaration of the
    composite type, conjoined with "and".}

      AARM Reason: {AI05-0028-1} The reason why we need {to
      specify the aspect} for private types, private extensions, and
      protected types is fairly clear: the properties of the full view
      determine whether the type has preelaborable initialization or
      not; in order to preserve privacy we need a way to express on the
      partial view that the full view is well-behaved. The reason why we
      need {to specify the aspect} for other composite types
      is more subtle: a nonnull override for Initialize might occur in
      the private part, even for a nonprivate type; in order to preserve
      privacy, we need a way to express on a type declared in a visible
      part that the private part does not contain any nasty override of
      Initialize.
  
  If the {Preelaborable_Initialization aspect is specified True for} a
  private type or a private extension, the full view of the type shall
  have preelaborable initialization. If the {aspect is specified True
  for} a protected type, the protected type shall not have entries, and
  each component of the protected type shall have preelaborable
  initialization. {If the aspect is specified True for a generic formal
  type, then in a generic_instantiation the corresponding actual type
  shall have preelaborable initialization. If the aspect is specified to
  be the conjunction of one or more Preelaborable_Initialization
  attribute references, then the full view of the type shall have
  preelaborable initialization presuming the types mentioned in the
  conjunction all have preelaborable initialization.} For any other
  composite type, the {aspect shall be specified statically True or False
  only if it is confirming}. In addition to the places where Legality
  Rules normally apply (see 12.3), these rules apply also in the private
  part of an instance of a generic unit.
  
    AARM Ramification: Not only do protected types with
    entry_declarations and task types not have preelaborable
    initialization, but they cannot have {the aspect}
    Preelaborable_Initialization {specified True for}
    them.

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

Questions? Ask the ACAA Technical Agent