Contents   Index   Search   Previous   Next

12.5.1 Formal Private and Derived Types

   [The class determined for a formal private type can be either limited or nonlimited, and either tagged or untagged; no more specific class is known for such a type. The class determined for a formal derived type is the derivation class rooted at the ancestor type.]


formal_private_type_definition ::= [[abstracttagged] [limitedprivate
formal_derived_type_definition ::= [abstractnew subtype_mark [with private]

Legality Rules

   If a generic formal type declaration has a known_discriminant_part, then it shall not include a default_expression for a discriminant.
Ramification: Consequently, a generic formal subtype with a known_discriminant_part is an indefinite subtype, so the declaration of a stand-alone variable has to provide a constraint on such a subtype, either explicitly, or by its initial value.
   {ancestor subtype (of a formal derived type)} The ancestor subtype of a formal derived type is the subtype denoted by the subtype_mark of the formal_derived_type_definition. For a formal derived type declaration, the reserved words with private shall appear if and only if the ancestor type is a tagged type; in this case the formal derived type is a private extension of the ancestor type and the ancestor shall not be a class-wide type. [Similarly, the optional reserved word abstract shall appear only if the ancestor type is a tagged type].
Reason: We use the term ``ancestor'' here instead of ``parent'' because the actual can be any descendant of the ancestor, not necessarily a direct descendant.
   If the formal subtype is definite, then the actual subtype shall also be definite.
Ramification: On the other hand, for an indefinite formal subtype, the actual can be either definite or indefinite.
   For a generic formal derived type with no discriminant_part:
Ramification: In other words, any constraint on the ancestor subtype is considered part of the ``contract.''
Reason: This rule ensures that if a composite constraint is allowed on the formal, one is also allowed on the actual. If the ancestor subtype is an unconstrained scalar subtype, the actual is allowed to be constrained, since a scalar constraint does not cause further constraints to be illegal.
Reason: This ensures that if a discriminant constraint is given on the formal subtype, the corresponding constraint in the instance will make sense, without additional run-time checks. This is not necessary for arrays, since the bounds cannot be overridden in a type extension. An unknown_discriminant_part may be used to relax these matching requirements.
    The declaration of a formal derived type shall not have a known_discriminant_part. For a generic formal private type with a known_discriminant_part:
Reason: We considered defining the first and third rule to be called ``subtype conformance'' for discriminant_parts. We rejected that idea, because it would require implicit (inherited) discriminant_parts, which seemed like too much mechanism.
    [For a generic formal type with an unknown_discriminant_part, the actual may, but need not, have discriminants, and may be definite or indefinite.]

Static Semantics

    The class determined for a formal private type is as follows:
Type Definition  Determined Class

limited private  the class of all types
private  the class of all nonlimited types
tagged limited private  the class of all tagged types
tagged private  the class of all nonlimited tagged types
    [The presence of the reserved word abstract determines whether the actual type may be abstract.]
    A formal private or derived type is a private or derived type, respectively. A formal derived tagged type is a private extension. [A formal private or derived type is abstract if the reserved word abstract appears in its declaration.]
    If the ancestor type is a composite type that is not an array type, the formal type inherits components from the ancestor type (including discriminants if a new discriminant_part is not specified), as for a derived type defined by a derived_type_definition (see 3.4).
      {8652/0038} For a formal derived type, the predefined operators and inherited user-defined subprograms are determined by the ancestor type, and are implicitly declared at the earliest place, if any, within the immediate scope of the formal type, where the corresponding primitive subprogram of the ancestor is visible (see 7.3.1). In an instance, the copy of such an implicit declaration declares a view of the corresponding primitive subprogram of the ancestor of the formal derived type , even if this primitive has been overridden for the actual type. When the ancestor of the formal derived type is itself a formal type, the copy of the implicit declaration declares a view of the corresponding copied operation of the ancestor. [In the case of a formal private extension, however, the tag of the formal type is that of the actual type, so if the tag in a call is statically determined to be that of the formal type, the body executed will be that corresponding to the actual type.]
Ramification: The above rule defining the properties of primitive subprograms in an instance applies even if the subprogram has been overridden or hidden for the actual type. This rule is necessary for untagged types, because their primitive subprograms might have been overridden by operations that are not subtype-conformant with the operations defined for the class. For tagged types, the rule still applies, but the primitive subprograms will dispatch to the appropriate implementation based on the type and tag of the operands. Even for tagged types, the formal parameter names and default_expressions are determined by those of the primitive subprograms of the specified ancestor type.
      For a prefix prefix S that denotes a formal indefinite subtype, the following attribute is defined:
S'Definite yields True if the actual subtype corresponding to S is definite; otherwise it yields False. The value of this attribute is of the predefined type Boolean.
Discussion: Whether an actual subtype is definite or indefinite may have a major effect on the algorithm used in a generic. For example, in a generic I/O package, whether to use fixed-length or variable-length records could depend on whether the actual is definite or indefinite. This attribute is essentially a replacement for the Constrained attribute which is now considered obsolete.
9  In accordance with the general rule that the actual type shall belong to the class determined for the formal (see 12.5, ``Formal Types''):
10  [The actual type can be abstract only if the formal type is abstract (see 3.9.3).]
Reason: This is necessary to avoid contract model problems, since one or more of its primitive subprograms are abstract; it is forbidden to create objects of the type, or to declare functions returning the type.
Ramification: On the other hand, it is OK to pass a non-abstract actual to an abstract formal -- abstract on the formal indicates that the actual might be abstract.
11  If the formal has a discriminant_part, the actual can be either definite or indefinite. Otherwise, the actual has to be definite.

Incompatibilities With Ada 83

{incompatibilities with Ada 83} Ada 83 does not have unknown_discriminant_parts, so it allows indefinite subtypes to be passed to definite formals, and applies a legality rule to the instance body. This is a contract model violation. Ada 95 disallows such cases at the point of the instantiation. The workaround is to add (<>) as the discriminant_part of any formal subtype if it is intended to be used with indefinite actuals. If that's the intent, then there can't be anything in the generic body that would require a definite subtype.
The check for discriminant subtype matching is changed from a run-time check to a compile-time check.

Contents   Index   Search   Previous   Next   Legal