3.10.1 Incomplete Type Declarations
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
Static Semantics
{
AI95-00326-01}
{incomplete type} {incomplete
view} An
incomplete_type_declaration
declares an
incomplete view of a type and its first subtype; the
first subtype is unconstrained if a
discriminant_part
appears. If the
incomplete_type_declaration
includes the reserved word
tagged, it declares a
tagged incomplete
view.
{incomplete view (tagged)}
{tagged incomplete
view} An incomplete view of a type is
a limited view of the type (see
7.5).
{
AI95-00326-01}
Given an access type
A whose designated type
T is an incomplete
view, a dereference of a value of type
A also has this incomplete
view except when:
it occurs within the immediate scope of the completion
of T, or
it occurs within the scope of a
nonlimited_with_clause
that mentions a library package in whose visible part the completion
of
T is declared.
In these cases, the dereference has the full view
of T.
Discussion:
We need the “in whose visible part” rule so that the
second rule doesn't trigger in the body of a package with a with
of a child unit:
package P is
private
type T;
type PtrT is access T;
end P;
private package P.C is
Ptr : PtrT;
end P.C;
with P.C;
package body P
is
--
Ptr.all'Size is not legal here, but it is in the scope of a
--
nonlimited_with_clause for P.
type T
is ...
--
Ptr.all'Size is legal here.
end P;
Legality Rules
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.
{
AI95-00326-01}
A
name that
denotes an incomplete view of a type may be used as follows:
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.
{
AI95-00326-01}
If such a
name
denotes a tagged incomplete view, it may also be used:
{
AI95-00326-01}
If such a
name
occurs within the declaration list containing the completion of the incomplete
view, it may also be used:
Reason: This allows, for example, a record
to have a component designating a subprogram that takes that same record
type as a parameter.
{
AI95-00326-01}
If any of the above uses occurs as part of the declaration of a primitive
subprogram of the incomplete view, and the declaration occurs immediately
within the private part of a package, then the completion of the incomplete
view shall also occur immediately within the private part; it shall not
be deferred to the package body.
Reason: This fixes a hole in Ada 95 where
a dispatching operation with an access parameter could be declared in
a private part and a dispatching call on it could occur in a child even
though there is no visibility on the full type, requiring access to the
controlling tag without access to the representation of the type.
{
AI95-00326-01}
No other uses of a
name
that denotes an incomplete view of a type are allowed.
Reason: We used to disallow all dereferences
of an incomplete type. Now we only disallow such dereferences when used
as a
prefix.
Dereferences used in other contexts do not pose a problem since normal
type matching will preclude their use except when the full type is “nearby”
as context (for example, as the expected type).
This also disallows
prefixes
that are directly of an incomplete view. For instance, a parameter
P
can be declared of a tagged incomplete type, but we don't want to allow
P'Size,
P'Alignment, or the like, as representation values
aren't known for an incomplete view.
We say “denotes an object” so that
prefixes that directly name an incomplete view are not covered; the previous
rules cover such cases, and we certainly don't want to ban Incomp'Class.
Static Semantics
Dynamic Semantics
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.
Examples
Example of a recursive
type:
type Cell; -- incomplete type declaration
type Link is access Cell;
type Cell is
record
Value : Integer;
Succ : Link;
Pred : Link;
end record;
Head : Link := new Cell'(0, null, null);
Next : Link := Head.Succ;
Examples of mutually dependent access types:
{
AI95-00433-01}
type Person(<>); --
incomplete type declaration
type Car
is tagged; --
incomplete type declaration
{
AI95-00433-01}
type Person_Name
is access Person;
type Car_Name
is access all Car'Class;
{
AI95-00433-01}
type Car
is tagged
record
Number : Integer;
Owner : Person_Name;
end record;
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;
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
A
discriminant_constraint
may be applied to an incomplete type, even if 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
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:
package Pack is
type Pri is private;
private
type Sep;
type Pri is access Sep;
X : Pri;
end Pack;
package body Pack is -- Could be separately compiled!
type Sep is ...;
X := new Sep;
end Pack;
pragma Elaborate(Pack);
private package Pack.Child is
I : Integer := X.all'Size; -- Legal, by AI-00039.
end Pack.Child;
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.
Incompatibilities With Ada 95
{
AI95-00326-01}
{
incompatibilities with Ada 95}
It is now
illegal to use an incomplete view (type) as the parameter or result of
an access-to-subprogram type unless the incomplete view is completed
in the same declaration list as the use. This was allowed in Ada 95 for
incomplete types where the completion was deferred to the body. By disallowing
this rare use of incomplete views, we can allow the use of incomplete
views in many more places, which is especially valuable for limited views.
{
AI95-00326-01}
It is now illegal to use an incomplete view (type) in a primitive subprogram
of the type unless the incomplete view is completed in the package specification.
This was allowed in Ada 95 for incomplete types where the completion
was deferred to the body (the use would have to be in an access parameter).
This incompatibility was caused by the fix for the hole noted in Legality
Rules above.
Extensions to Ada 95
{
AI95-00326-01}
{
extensions to Ada 95}
Tagged incomplete types
are new. They are allowed in parameter declarations as well as the usual
places, as tagged types are always by-reference types (and thus there
can be no code generation issue).
Wording Changes from Ada 95
{
AI95-00326-01}
The description of incomplete types as
incomplete views is new.
Ada 95 defined these as separate types, but neglected to give any rules
for matching them with other types. Luckily, implementers did the right
thing anyway. This change also makes it easier to describe the meaning
of a limited view.