Version 1.20 of ais/ai-00161.txt

Unformatted version of ais/ai-00161.txt version 1.20
Other versions for file ais/ai-00161.txt

!standard 10.02.01 (04)          05-12-01 AI95-00161/13
!standard 10.02.01 (09)
!standard 10.02.01 (11)
!standard 7.06 (05)
!standard 7.06 (07)
!standard 13.07 (34)
!standard 13.11 (06)
!standard 13.13.1 (03)
!standard A.04.02 (04)
!standard A.04.02 (20)
!standard A.04.05 (04)
!standard A.04.07 (04)
!standard A.04.07 (20)
!standard B.03.01 (05)
!standard C.04 (04)
!standard G.01.01 (04)
!class binding interpretation 99-02-23
!status Amendment 200Y 02-07-10
!status WG9 Approved 02-06-21
!status ARG Approved 7-0-1 01-10-07
!status work item 98-04-16
!status received 96-09-10
!priority Medium
!difficulty Medium
!subject Default-initialized objects
!summary
The creation of an object whose type has preelaborable initialization is allowed in a preelaborable unit. This makes it possible to declare objects of some private types in preelaborable units.
The notion of a type having "preelaborable initialization" and the pragma Preelaborable_Initialization are defined by this AI.
!question
The paragraphs 10.2.1(5-9) list a number of constructs which are forbidden in preelaborable units. In particular, 10.2.1(9) forbids: "The creation of a default-initialized object (including a component) of a descendant of a private type, private extension, controlled type, task type, or protected type with entry_declarations;".
1. In this rule, what is the meaning of "default-initialized object"?
2. This rule seems extremely restrictive. For instance, if (as recommended by the standard) System.Address is a private type, the declaration:
A : System.Address;
makes the enclosing unit non-preelaborable. As another example, the implementation of Ada.Strings.Unbounded suggested in the Rationale is impossible because the initial value for the deferred constant Null_Unbounded_String would have to include an extension aggregate for a controlled type, which is illegal in a preelaborable unit.
!recommendation
(See wording.)
!wording
Change the 10.2.1(9) to read: "The creation of an object (including a component) of a type that does not have preelaborable initialization. Similarly, the evaluation of an extension_aggregate with an ancestor subtype_mark denoting a subtype of such a type."
Add a new bullet after C.4(4): "No subtype_mark denotes a controlled type, a private type, a private extension, a generic formal private type, a generic formal derived type, or a descendant of such a type."
Add the following after 10.2.1(11/1):
"The following rules specify which entities have preelaborable initialization:
- 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, have preelaborable initialization if and only if the pragma Preelaborable_Initialization has been applied to them. A protected type with entry_declarations or a task type never 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 of the actions listed in 10.2.1(6-9), 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 (in the case of a derived record extension) if the non-inherited components all have preelaborable initialization. However, a user-defined controlled type with an overriding Initialize 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, or a record type whose components all have preelaborable initialization.
A pragma Preelaborable_Initialization specifies that a type has preelaborable initialization. The form of this pragma is as follows:
pragma Preelaborable_Initialization (direct_name);
This pragma must 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 private type, private extension, or protected type without entry_declarations, and the type shall be declared immediately within the same package as the pragma. If the pragma is applied to a private type or a private extension, the full view of the type shall have preelaborable initialization. If the pragma is applied to a protected type, each component of the protected type shall have preelaborable initialization. In addition to the places where Legality Rules normally apply, 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 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."
!discussion
1. A "default-initialized object" is an object for which the implicit initialization described in 3.3.1(10-14) takes place. Examples of default-initialized objects include an object_declaration without an initialization expression, and the (anonymous) object created by the evaluation of an extension_aggregate whose ancestor_part is a subtype name.
Note that an object of a task type or of a protected type is always default- initialized. Also note that for a private type or a private extension, providing an initialization expression always requires a reference to the name of an object, or a call to a non-static function, which are forbidden by other rules. Finally note that for a controlled type, an initialization expression may also be provided by an extension aggregate (if visibility allows), which must have a controlled subtype name as the ancestor part, which is forbidden.
The conclusion is that the phrase "default-initialized" can be removed from 10.2.1(9).
2. 10.2.1(9) is indeed too restrictive. For preelaboration to be usable (in particular in the context of distributed systems) we must loosen up the rules dramatically. However, we do not want to impose an additional burden on implementations which support annex C and have to comply with the requirements of C.4. Therefore, each time we remove a restriction from 10.2.1(9), we must add a corresponding restriction to C.4.
Clearly we must keep task objects and protected objects with entries in 10.2.1(9). Note that the current wording seems to allow the creation of objects of entry-less protected types, which is strange since the component_declarations may include default_expressions which execute non- trivial code.
To precisely specify which object declarations are acceptable in a preelaborable unit, we introduce the notion of a type having preelaborable initialization. In order to take advantage of the fact that some two-part types (such as private types and private extensions) may have preelaborable initialization, without breaking the privacy of private types, we introduce the pragma Preelaborable_Initialization. This pragma is applied to the partial view, and it promises that the full view will have preelaborable initialization. This pragma is applied to some of the predefined private types, to make it easier for users to write preelaborable units.
The following table lists all the private types and private extensions declared in preelaborated predefined packages. For each such type, the table specifies if a pragma Preelaborable_Initialization is applied to the type (yes) or not (no). For those packages that have a Wide_ variant, the types declared in the Wide_ variant have the same classification as the types declared in the 'narrow' variant. The same remark applies to the non-generic equivalents of the various generic packages.
Ada.Finalization.Controlled yes Ada.Finalization.Limited_Controlled yes Ada.Numerics.Generic_Complex_Types.Imaginary yes Ada.Streams.Root_Stream_Type yes Ada.Strings.Bounded.Generic_Bounded_Length.Bounded_String no Ada.Strings.Maps.Character_Mapping yes Ada.Strings.Maps.Character_Set yes Ada.Strings.Unbounded.Unbounded_String yes Interfaces.C.Strings.Chars_Ptr yes System.Address yes* System.Storage_Pool.Root_Storage_Pool yes
(*) Type System.Address *might* be a private type. As such, we simply say that it has preelaborable initialization, and leave it to the implementation to figure out how to accomplish that. We don't want to apply the pragma to it, because it might not be a type that allows the pragma.
Note: The type Bounded_String cannot have a pragma Preelaborable_Initialization, because that would make it impossible to instantiate Generic_Bounded_Length with a non-static expression for the parameter Max.
!corrigendum 7.06(05)
Replace the paragraph:
type Controlled is abstract tagged private;
by:
type Controlled is abstract tagged private; pragma Preelaborable_Initialization(Controlled);
!corrigendum 7.06(07)
Replace the paragraph:
type Limited_Controlled is abstract tagged limited private;
by:
type Limited_Controlled is abstract tagged limited private; pragma Preelaborable_Initialization(Limited_Controlled);
!corrigendum 10.02.01(4)
Insert after the paragraph:
A pragma Preelaborate is a library unit pragma.
the new paragraphs:
The form of a pragma Preelaborable_Initialization is as follows:
 pragma Preelaborable_Initialization(direct_name);
!corrigendum 10.02.01(9)
Replace the paragraph:
by:
!corrigendum 10.02.01(11/1)
Insert after the paragraph:
If a pragma Preelaborate (or pragma Pure -- see below) applies to a library unit, then it is preelaborated. If a library unit is preelaborated, then its declaration, if any, and body, if any, are elaborated prior to all non-preelaborated library_items of the partition. 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. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit. In addition, all compilation units of a preelaborated library unit shall depend semantically only on compilation units of other preelaborated library units.
the new paragraphs:
The following rules specify which entities have preelaborable initialization:
A pragma Preelaborable_Initialization specifies that a type has preelaborable initialization. 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 private type, private extension, or protected type without entry_declarations, and the type shall be declared immediately within the same package as the pragma. If the pragma is applied to a private type or a private extension, the full view of the type shall have preelaborable initialization. If the pragma is applied to a protected type, each component of the protected type shall have preelaborable initialization. In addition to the places where Legality Rules normally apply, 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 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.
!corrigendum 13.07(34)
Replace the paragraph:
Address is of a definite, nonlimited type. Address represents machine addresses capable of addressing individual storage elements. Null_Address is an address that is distinct from the address of any object or program unit.
by:
Address is a definite, nonlimited type with preelaborable initialization (see 10.2.1). Address represents machine addresses capable of addressing individual storage elements. Null_Address is an address that is distinct from the address of any object or program unit.
!corrigendum 13.11(06)
Replace the paragraph:
type Root_Storage_Pool is abstract new Ada.Finalization.Limited_Controlled with private;
by:
type Root_Storage_Pool is abstract new Ada.Finalization.Limited_Controlled with private; pragma Preelaborable_Initialization(Root_Storage_Pool);
!corrigendum 13.13.1(03)
Replace the paragraph:
type Root_Stream_Type is abstract tagged limited private;
by:
type Root_Stream_Type is abstract tagged limited private; pragma Preelaborable_Initialization(Root_Stream_Type);
!corrigendum A.4.2(04)
Replace the paragraph:
-- Representation for a set of character values: type Character_Set is private;
by:
-- Representation for a set of character values: type Character_Set is private; pragma Preelaborable_Initialization(Character_Set);
!corrigendum A.4.2(20)
Replace the paragraph:
-- Representation for a character to character mapping: type Character_Mapping is private;
by:
-- Representation for a character to character mapping: type Character_Mapping is private; pragma Preelaborable_Initialization(Character_Mapping);
!corrigendum A.4.5(04)
Replace the paragraph:
type Unbounded_String is private;
by:
type Unbounded_String is private; pragma Preelaborable_Initialization(Unbounded_String);
!corrigendum A.4.7(04)
Replace the paragraph:
-- Representation for a set of Wide_Character values: type Wide_Character_Set is private;
by:
-- Representation for a set of Wide_Character values: type Wide_Character_Set is private; pragma Preelaborable_Initialization(Wide_Character_Set);
!corrigendum A.4.7(20)
Replace the paragraph:
-- Representation for a Wide_Character to Wide_Character mapping: type Wide_Character_Mapping is private;
by:
-- Representation for a Wide_Character to Wide_Character mapping: type Wide_Character_Mapping is private; pragma Preelaborable_Initialization(Wide_Character_Mapping);
!corrigendum B.3.1(05)
Replace the paragraph:
type chars_ptr is private;
by:
type chars_ptr is private; pragma Preelaborable_Initialization(chars_ptr);
!corrigendum C.4(4)
Insert after the paragraph:
the new paragraph:
!corrigendum G.1.1(04)
Replace the paragraph:
type Imaginary is private;
by:
type Imaginary is private; pragma Preelaborable_Initialization(Imaginary);
!ACATS test
A C-Test is needed to test the newly legal cases allowed by this AI. B-Test BA21A02 checks for the (still) illegal cases.
!appendix

!section 10.2.1(9)
!subject Default-initialized objects
!reference RM95-10.2.1(9)
!from Pascal Leroy 96-08-30
!reference 96-5697.a Pascal Leroy 96-9-10>>
!discussion

The referenced paragraph says that a construct is not preelaborable if it
performs "The creation of a default-initialized object (including a component)
of a descendant of a private type, private extension, controlled type, task
type or protected type with entry declarations;"

In this rule, what is the meaning of "default-initialized object"?  I couldn't
find a definition of this phrase.

Bob Duff (private communication) tells me that this phrase is intended to
cover (among other things?) an object declaration which doesn't have an
initialization expression.

Even accepting this interpretation, there remain open questions.  For
instance: is an object to which a pragma Import is applied a
default-initialized object?  B.1(38) and B.1(24) say that no initialization
occurs in this case, so it would seem that the answer is 'no'.

It is interesting to note that, with this interpretation, 10.2.1(9) becomes
very restrictive: for a private type, a private extension or a controlled
type, I am not sure how one could write an initial value without either
referencing the name of an object, calling a non-static function, or writing
an extension aggregate.  But these things are forbidden by 10.2.1(7-9).  So
10.2.1 seems to state that (except in the case of imported objects) a
preelaborable units can never declare an object of a private type, a private
extension, or a controlled type.  Is it the intent?

(It looks like all objects of task or protected types are
"default-initialized", so the rule is redundant.  But that's not important:
it
is clear that we don't want objects of such types in preelaborated units.)

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

From:   Randy Brukardt [SMTP:Randy@rrsoftware.com]
Sent:   Thursday, May 07, 1998 8:12 PM
Subject:        Re: AI95-00161/02

This AI has class "Confirmation", yet proposes language which extends the
language (allowing things previously disallowed).  I wouldn't expect
"Confirmation" Ais to have wording changes.  Shouldn't this AI be
re-classified?

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

From:   Pascal Leroy[SMTP:phl@Rational.Com]
Sent:   Friday, May 08, 1998 6:04 AM
Subject:        Re: AI95-00161/02

> This AI has class "Confirmation", yet proposes language which extends the
> language (allowing things previously disallowed).  I wouldn't expect
> "Confirmation" Ais to have wording changes.  Shouldn't this AI be
> re-classified?

Surely it should be a binding interpretation.  Thanks for noticing.

Pascal

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

From: 	Tucker Taft
Sent: 	Friday, February 26, 1999 9:47 AM
Subject: 	Re: Updated AIs

In AI 131, you have proposed that entry-less protected
objects are not preelaborable.  This is a troublesome
change, as Shared_Passive packages are required to
be preelaborable, and entry-less protected objects are
the only means of synchronization available via a
Shared_Passive partition.

Hence, the AI needs to accommodate entry-less protected objects
somehow, ideally without causing incompatibilities with
existing code which uses Shared_Passive packages, though
that goal may not be achievable...

-Tuck

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

From: 	Randy Brukardt
Sent: 	Friday, February 26, 1999 3:06 PM
Subject: 	RE: Updated AIs

Tucker writes:

>In AI 131, you have proposed that entry-less protected
>objects are not preelaborable.

You mean AI 161. 131 is on interfacing to C.

Randy's comments on AI-161:

There is something wrong with the Wording change in this AI, as it depends on the
(undefined) term "preelaboratable initialization". I think the entire definition of this
term, and the pragma, needs to be moved to the "Wording" section. That would
leave just the actual discussion behind, not the technical definition.

				Randy.

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

From: 	Pascal Leroy
Sent: 	Monday, March 01, 1999 4:16 AM

Yeah, I know someone would notice...

The reason why I didn't structure the AI in this way is that I was under the
impression that the stuff in !discussion was insufficiently rigorous for a
!wording section.  But then you're right: having the wording depend on an
undefined term is not too good.

Pascal

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

From: 	Pascal Leroy
Sent: 	Monday, March 01, 1999 4:14 AM

> In AI 161, you have proposed that entry-less protected
> objects are not preelaborable.  This is a troublesome
> change, as Shared_Passive packages are required to
> be preelaborable, and entry-less protected objects are
> the only means of synchronization available via a
> Shared_Passive partition.

This was a mistake.  My intent was _not_ to make them non-preelaborable.

However, now that you have drawn my attention to this topic, I believe there
is a specific problem with protected objects.  The private part of a protected
object may include default expressions for components, and these default
expressions may or may not be preelaborable.  We need to decide if we want to
respect the privacy of the private part of protected objects.  If we do, it
seems that the pragma should apply in this case too: i.e., in the absence of a
pragma, the declaration of a protected object should be non-preelaborable; if
on the other hand you use the pragma, then the private part must have
preelaborable initialization.

What do you think?

Pascal

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

From: 	Tucker Taft
Sent: 	Monday, March 01, 1999 8:18 AM

> > In AI 161, you have proposed that entry-less protected
> > objects are not preelaborable.  This is a troublesome
> > change, as Shared_Passive packages are required to
> > be preelaborable, and entry-less protected objects are
> > the only means of synchronization available via a
> > Shared_Passive partition.
>
> This was a mistake.  My intent was _not_ to make them non-preelaborable.
>
> However, now that you have drawn my attention to this topic, I believe there
> is a specific problem with protected objects.  The private part of a protected
> object may include default expressions for components, and these default
> expressions may or may not be preelaborable.  We need to decide if we want to
> respect the privacy of the private part of protected objects.  If we do, it
> seems that the pragma should apply in this case too: i.e., in the absence of a
> pragma, the declaration of a protected object should be non-preelaborable; if
> on the other hand you use the pragma, then the private part must have
> preelaborable initialization.
>
> What do you think?

Yes, I suppose the pragma ought to apply to entry-less protected
types in the same way it applies to private types.  On the other
hand, there seems no need for the pragma for a singleton protected
object, since the only use of the type is for that object, and
if that object is in a preelaborated package, clearly the
default initialization needs to be preelaborable.

-Tuck

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

!topic Suggested implementation of Ada.Strings.Unbounded, Preelaborate
!reference RM95-A.4.5(3), 10.2.1(9); AARM95-A.4.5; Rationale A.2.6
!from Adam Beneschan 03-29-02
!discussion

In the AARM, Section A.4.5 (describing Ada.Strings.Unbounded) ends
with the comment, "A sample implementation of the private part of the
package and several of the subprograms appears in the Rationale."

The package defines a constant Null_Unbounded_String.  In the
Rationale, section A.2.6 (see http://www.adaic.org/standards/95rat/
RAThtml/rat95-p3-a.html#2), the suggested implementation defines the
constant this way, in the private part:

    Null_Unbounded_String : constant Unbounded_String :=
      (Controlled with Reference => Null_String'Access);

where Controlled is Ada.Finalization.Controlled.

However, it appears to me that this suggestion is illegal.
RM95-A.4.5(3) says that Ada.Strings.Unbounded has a Preelaborate
pragma, which means it must be preelaborable, which means, according
to 10.2.1(9), that the elaboration of the package must not evaluate an
extension_aggregate with an ancestor subtype_mark denoting a subtype
of a controlled type.  The above constant declaration violates this
rule.  (3.4.1(10) defines a type to be a descendant of itself, and
Ada.Finalization.Controlled is a controlled type by 7.6(9).)

Is my interpretation incorrect?  It seems strange to me that an
implementation which is suggested by an official document (and also
seems to be the natural way to implement the constant) should be
illegal.

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

From: 	Pascal Leroy
Sent: 	Saturday, March 30, 2002  2:30 AM

This is a problem that has been known for about 8 years and is addressed by
AI 161.  I guess the folks who wrote the Rationale didn't have, at the time,
a full-fledged Ada compiler to check the code examples.

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

From: 	Robert Dewar
Sent: 	Saturday, March 30, 2002  8:04 AM

Indeed this problem is well known :-)

What we do in GNAT is to use the illegal code as given, but then we have a
special kludge in the compiler to allow this for internal implementation
units (there is no rule in the RM that requires library packages to be
written in Ada :-)

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

!topic Preelaborable_Initialization(System.Address) may be illegal
!reference RM05 10.2.1(11.7/2), 13.7(12/2), 13.7(37)
!from Adam Beneschan 05-12-09
!discussion

Minor nitpick in the Amendment:

13.7 gives the definition of Address, in package System, as:

   type Address is <implementation-defined>;
   pragma Preelaborable_Initialization(Address);

The Implementation Advice in 13.7(37) says that Address should be a
private type, but does not require this.  If an implementation ignores
this advice and defines it in a different way, the
Preelaborable_Initialization pragma is most likely illegal, since
10.2.1(11.7/2) allows this pragma to be applied only to private types,
private extensions, and entryless protected types.

This is probably not be a major issue---if there are any
implementations left that don't define Address as a private type, they
will almost certainly define it as a type that will have preelaborable
initialization by the rules of 10.2.1.  (For such implementations,
does there need to be a rule explicitly stating that [the partial view
of] System.Address shall have preelaborable initialization?)  Also,
there's no requirement that language-defined packages have to be
compiled using an Ada compiler that obeys all the language rules.
Still, it looks a little bad (in my opinion) to have 13.7 give, as
part of the definition of a language-defined package, an Ada construct
that may be illegal.

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

From: 	Pascal Leroy
Sent: 	Saturday, December 10, 2005  5:33 AM

Good point.  I think we should remove the pragma from the spec of System
and add a sentence at the end of 13.7(34):

	Address has preelaborable initialization (see 10.2).

In the case where address is private, this means that the pragma must be
applied to it.  However, if address is, say, a scalar, it has
preelaborable initialization by fiat.

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


Questions? Ask the ACAA Technical Agent