Contents Index Previous Next
3.10.1 Incomplete Type Declarations
1
There are no particular limitations on the designated
type of an access type. In particular, the type of a component of the
designated type can be another access type, or even the same access type.
This permits mutually dependent and recursive access types. An incomplete_type_declaration
can be used to introduce a type to be used as a designated type, while
deferring its full definition to a subsequent full_type_declaration.
Syntax
2
incomplete_type_declaration
::= type defining_identifier [
discriminant_part];
Legality Rules
3
{requires a completion (incomplete_type_declaration)
[partial]} An
incomplete_type_declaration
requires a completion, which shall be a
full_type_declaration.
[If the
incomplete_type_declaration
occurs immediately within either the visible part of a
package_specification
or a
declarative_part, then the
full_type_declaration shall occur
later and immediately within this visible part or
declarative_part.
If the
incomplete_type_declaration
occurs immediately within the private part of a given
package_specification,
then the
full_type_declaration shall
occur later and immediately within either the private part itself, or
the
declarative_part of the corresponding
package_body.]
3.a
Proof: This is implied by the next
AARM-only rule, plus the rules in 3.11.1, ``Completions
of Declarations'' which require a completion to appear later and immediately
within the same declarative region.
3.b
To be honest: If the incomplete_type_declaration
occurs immediately within the visible part of a package_specification,
then the full_type_declaration shall
occur immediately within this visible part.
3.c
To be honest: If the implementation
supports it, an incomplete_type_declaration
can be completed by a pragma Import.
4
If an
incomplete_type_declaration
has a
known_discriminant_part, then a
full_type_declaration
that completes it shall have a fully conforming (explicit)
known_discriminant_part
(see
6.3.1).
{full conformance
(required)} [If an
incomplete_type_declaration
has no
discriminant_part (or an
unknown_discriminant_part),
then a corresponding
full_type_declaration
is nevertheless allowed to have discriminants, either explicitly, or inherited
via derivation.]
5
The only allowed
uses of a name that denotes an incomplete_type_declaration
are as follows:
5.a
Discussion: No need to
say "prior to the end of the full_type_declaration"
since the name would not denote the incomplete_type_declaration
after the end of the full_type_declaration.
Also, with child library units, it would not be well defined whether
they come before or after the full_type_declaration
for deferred incomplete types.
6
- as the subtype_mark
in the subtype_indication of an
access_to_object_definition; [the
only form of constraint allowed
in this subtype_indication is a
discriminant_constraint;]
6.a
Implementation Note: We
now allow discriminant_constraints
even if the full type is deferred to the package body. However, there
is no particular implementation burden because we have dropped the concept
of the dependent compatibility check. In other words, we have effectively
repealed AI83-00007.
7
- as the subtype_mark
defining the subtype of a parameter or result of an access_to_subprogram_definition;
7.a
Reason: This allows, for
example, a record to have a component designating a subprogram that takes
that same record type as a parameter.
8
- as the subtype_mark
in an access_definition;
9
- as the prefix of an
attribute_reference whose attribute_designator
is Class; such an attribute_reference
is similarly restricted to the uses allowed here; when used in this way,
the corresponding full_type_declaration
shall declare a tagged type, and the attribute_reference
shall occur in the same library unit as the incomplete_type_declaration.
9.a
Reason: This is to prevent
children from imposing requirements on their ancestor library units for
deferred incomplete types.
10
A dereference (whether implicit or
explicit -- see
4.1) shall not be of an incomplete
type.
Static Semantics
11
{incomplete type}
An
incomplete_type_declaration
declares an incomplete type and its first subtype; the first subtype
is unconstrained if a
known_discriminant_part
appears.
11.a
Reason: If an unknown_discriminant_part
or no discriminant_part appears,
then the constrainedness of the first subtype doesn't matter for any
other rules or semantics, so we don't bother defining it. The case with
a known_discriminant_part is the
only case in which a constraint could later be given in a subtype_indication
naming the incomplete type.
Dynamic Semantics
12
{elaboration (incomplete_type_declaration)
[partial]} The elaboration of an
incomplete_type_declaration
has no effect.
12.a
Reason: An incomplete type
has no real existence, so it doesn't need to be "created" in
the usual sense we do for other types. It is roughly equivalent to a
"forward;" declaration in Pascal. Private types are different,
because they have a different set of characteristics from their full
type.
13
80 {completion legality
[partial]} Within a declarative_part,
an incomplete_type_declaration and a corresponding
full_type_declaration cannot be separated
by an intervening body. This is because a type has to be completely defined
before it is frozen, and a body freezes all types declared prior to it in the
same declarative_part (see 13.14).
Examples
14
Example of a
recursive type:
15
type Cell; -- incomplete type declaration
type Link is access Cell;
16
type Cell is
record
Value : Integer;
Succ : Link;
Pred : Link;
end record;
17
Head : Link := new Cell'(0, null, null);
Next : Link := Head.Succ;
18
Examples of mutually dependent access types:
19
type Person(<>); -- incomplete type declaration
type Car; -- incomplete type declaration
20
type Person_Name is access Person;
type Car_Name is access all Car;
21
type Car is
record
Number : Integer;
Owner : Person_Name;
end record;
22
type Person(Sex : Gender) is
record
Name : String(1 .. 20);
Birth : Date;
Age : Integer range 0 .. 130;
Vehicle : Car_Name;
case Sex is
when M => Wife : Person_Name(Sex => F);
when F => Husband : Person_Name(Sex => M);
end case;
end record;
23
My_Car, Your_Car, Next_Car : Car_Name := new Car; -- see 4.8
George : Person_Name := new Person(M);
...
George.Vehicle := Your_Car;
Extensions to Ada 83
23.a
{extensions to Ada 83}
The full_type_declaration
that completes an incomplete_type_declaration
may have a known_discriminant_part
even if the incomplete_type_declaration
does not.
23.b/1
A discriminant_constraint
may be applied to an incomplete type, even if it its completion
is deferred to the package body, because there is no ``dependent compatibility
check'' required any more. Of course, the constraint can be specified
only if a known_discriminant_part
was given in the incomplete_type_declaration.
As mentioned in the previous paragraph, that is no longer required even
when the full type has discriminants.
Wording Changes from Ada 83
23.c
Dereferences
producing incomplete types were not explicitly disallowed in RM83, though
AI83-00039 indicated that it was not strictly necessary since troublesome
cases would result in Constraint_Error at run time, since the access
value would necessarily be null. However, this introduces an undesirable
implementation burden, as illustrated by Example 4 of AI83-00039:
23.d
package Pack is
type Pri is private;
private
type Sep;
type Pri is access Sep;
X : Pri;
end Pack;
23.e
package body Pack is -- Could be separately compiled!
type Sep is ...;
X := new Sep;
end Pack;
23.f
pragma Elaborate(Pack);
private package Pack.Child is
I : Integer := X.all'Size; -- Legal, by AI-00039.
end Pack.Child;
23.g
Generating code for the above
example could be a serious implementation burden, since it would require
all aliased objects to store size dope, and for that dope to be in the
same format for all kinds of types (or some other equivalently inefficient
implementation). On the contrary, most implementations allocate dope
differently (or not at all) for different designated subtypes.
Contents Index Previous Next Legal