!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 '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 > '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 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. ****************************************************************