Contents   Index   Search   Previous   Next

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.


incomplete_type_declaration ::= type defining_identifier [discriminant_part];

Legality Rules

   {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.]
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.
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.
To be honest: If the implementation supports it, an incomplete_type_declaration can be completed by a pragma Import.
   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.]
   The only allowed uses of a name that denotes an incomplete_type_declaration are as follows:
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.
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.
Reason: This allows, for example, a record to have a component designating a subprogram that takes that same record type as a parameter.
Reason: This is to prevent children from imposing requirements on their ancestor library units for deferred incomplete types.
    A dereference (whether implicit or explicit -- see 4.1) shall not be of an incomplete type.

Static Semantics

    {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.
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

    {elaboration (incomplete_type_declaration) [partial]} The elaboration of an incomplete_type_declaration has no effect.
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.
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).


    Example of a recursive type:
type Cell;  --  incomplete type declaration
type Link is access Cell;
type Cell is
      Value  : Integer;
      Succ   : Link;
      Pred   : Link;
   end record;
Head   : Link  := new Cell'(0, nullnull);
Next   : Link  := Head.Succ;
    Examples of mutually dependent access types:
type Person(<>);    -- incomplete type declaration
type Car;           -- incomplete type declaration
type Person_Name is access Person;
type Car_Name    is access all Car;
type Car is
      Number  : Integer;
      Owner   : Person_Name;
   end record;
type Person(Sex : Gender) is
      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

{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.
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

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;
    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.

Contents   Index   Search   Previous   Next   Legal