12.5.1 Formal Private and Derived Types
[In its most general form, the category The
determined for a formal private type is
all types, but the category it can be restricted to only nonlimited types or to only tagged types can
be either limited or nonlimited, and either tagged or untagged; no more
specific class is known for such a type
. Similarly, the category for a formal incomplete type is all types but
the category can be restricted to only tagged types; unlike other formal
types, the actual type does not need to be able to be frozen (see 13.14).
The category class
determined for a formal derived type is the derivation class rooted at
the ancestor type.]
The first two rules
is given normatively below, and the
third second rule is given normatively in 12.5; they are
repeated here to give a capsule summary of what this subclause is about.
Since the actual of a formal incomplete type does
not need to be able to be frozen, the actual can be an incomplete type
or a partial view before it's completion.
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.
The ancestor subtype
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, an
the optional reserved words word
abstract or synchronized
appear only if the ancestor type is a tagged type]. The reserved word limited or synchronized shall appear
only if the ancestor type [and any progenitor types] are limited types.
The reserved word synchronized shall appear (rather than limited)
if the ancestor type or any of the progenitor types are synchronized
interfaces. The ancestor type shall be a
limited interface if the reserved word synchronized appears.
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.
We require the ancestor type to be limited when
limited appears so that we avoid oddities oddies like limited integer types. Normally, limited means “match
anything” for a generic formal, but it was felt that allowing limited
elementary types to be declared was just too weird. Integer still matches
a formal limited private type; it is only a problem when the type is
known to be elementary. Note that the progenitors are required to be
limited by rules in 3.9.4, thus that part
of the rule is redundant.
We require that synchronized appear if the
ancestor or any of the progenitors are synchronized, so that property
is explicitly given in the program text – it is not automatically
inherited from the ancestors. However, it can be given even if neither
the ancestor nor the progenitors are synchronized.
The actual type for a formal derived type shall
be a descendant of [the ancestor type and] every progenitor of the formal
type. If the formal type is nonlimited,
the actual type shall be nonlimited. If
the reserved word synchronized appears in the declaration of the
formal derived type, the actual type shall be a synchronized tagged type.
Proof: The actual
type has to be a descendant of the ancestor type, in order that it be
in the correct class. Thus, that part of the rule is redundant.
For a non-formal private extension, we require
the partial view to be synchronized if the full view is synchronized
tagged. This does not apply to a formal private extension — it
is OK if the formal is not synchronized. Any attempt to extend the formal
type will be rechecked in the instance, where the rule disallowing extending
a synchronized sychronized non-interface type will be enforced. This is consistent with the “no
hidden interfaces” rule also applying only to non-formal private
extensions, as well as the rule that a limited non-formal private extension
implies a limited full type. Formal private extensions are exempted from
all these rules to enable the construction of generics that can be used
with the widest possible range of types. In particular, an indefinite
tagged limited formal private type can match any “concrete”
actual tagged type.
A type (including formal types) derived from a
limited interface could be nonlimited; we do not want a limited type
derived from such an interface to match a nonlimited formal derived type.
Otherwise, we could assign limited objects. Thus, we have to explicitly
ban this case.
If a the
formal private or derived
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.
declares a formal incomplete type. The only view of a formal incomplete
type is an incomplete view. [Thus, a formal incomplete type is subject
to the same usage restrictions as any other incomplete type — see
If the ancestor subtype is constrained, the actual
subtype shall be constrained, and shall be statically compatible with
Ramification: In other words, any constraint
on the ancestor subtype is considered part of the “contract.”
If the ancestor subtype is an unconstrained access
or composite subtype, the actual subtype shall be unconstrained.
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.
If the ancestor subtype is an unconstrained discriminated
subtype, then the actual shall have the same number of discriminants,
and each discriminant of the actual shall correspond to a discriminant
of the ancestor, in the sense of 3.7
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.
If the ancestor subtype is an access subtype, the
actual subtype shall exclude null if and only if the ancestor subtype
Reason: We require
that the “excludes null” property match, because it would
be difficult to write a correct generic for a formal access type without
knowing this property. Many typical algorithms and techniques will not
work for a subtype that excludes null (setting an unused component to
null, default-initialized objects, and so on). We want this sort
of requirement to be reflected in the contract of the generic.
The actual type shall be a type with the same number
The actual subtype shall be unconstrained.
The subtype of each discriminant of the actual
type shall statically match the subtype of the corresponding discriminant
of the formal type.
We considered defining the first
and third rule to be called “subtype conformance” for discriminant_part
We rejected that idea, because it would require implicit (inherited)
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
The category class
determined for a formal private type is as follows:
Type Definition Determined Category Class
limited private the category class of all types
private the category class of all nonlimited types
tagged limited private the category class of all tagged types
tagged private the category class of all nonlimited tagged types
[The presence of the reserved word abstract
determines whether the actual type may be abstract.]
The category determined for a formal incomplete
type is the category of all types, unless the formal_type_declaration
includes the reserved word tagged; in this case, it is the category
of all tagged types.
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.]
For a formal derived type, the characteristics If
the ancestor type is a composite type that is not an array type, the
formal type inherits components from the ancestor type
components, but excluding
if there is
a new discriminant_part is not specified
), predefined operators,
and inherited user-defined primitive subprograms are determined by its
ancestor type and its progenitor types (if any), in the same way that
those of as for
a derived type are
determined by those of its parent type and its progenitor types defined
by a derived_type_definition
(see 3.4 and 7.3.1
For a formal derived type, the predefined operators
and inherited user-defined subprograms are determined by the ancestor
type and any progenitor
types, and are implicitly declared
at the earliest place, if any, immediately
within the declarative region in which within
the immediate scope of the formal type is declared, where the corresponding
primitive subprogram of the ancestor or
progenitor is visible (see 7.3.1).
In an instance, the copy of such
implicit declaration of a primitive subprogram
of a formal derived type
declares a view of the corresponding
primitive subprogram of the ancestor or progenitor of the formal derived type
even if this primitive has been overridden for the actual type and even if it is never declared for the actual type
the ancestor or progenitor 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 or progenitor.
[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.]
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 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_expression
are determined by those of the primitive subprograms of the specified
ancestor type (or progenitor type, for subprograms
inherited from an interface type)
For a prefix prefix
S that denotes a formal indefinite subtype, the following attribute is
S'Definite yields True if the actual subtype corresponding to S is definite;
it yields False. The value of
this attribute is of the predefined type Boolean.
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.
In the case where a formal type has is
tagged with unknown discriminants,
and the actual type is a class-wide type T'Class:
For the purposes of defining the primitive operations
of the formal type, each of the primitive operations of the actual type
is considered to be a subprogram (with an intrinsic calling convention
— see 6.3.1) whose body consists of
a dispatching call upon the corresponding operation of T, with
its formal parameters as the actual parameters. If it is a function,
the result of the dispatching call is returned.
If the corresponding operation of T has
no controlling formal parameters, then the controlling tag value is determined
by the context of the call, according to the rules for tag-indeterminate
calls (see 3.9.2 and 5.2).
In the case where the tag would be statically determined to be that of
the formal type, the call raises Program_Error. If such a function is
renamed, any call on the renaming raises Program_Error.
it states in 6.3.1, the convention of an
inherited subprogram of a generic formal tagged type with unknown discriminants
the case of a corresponding primitive of T with no controlling formal
parameters, the context of the call provides the controlling tag value
for the dispatch. If no tag is provided by context, Program_Error is
raised rather than resorting to a nondispatching call. For example:
type NT(<>) is new T with private;
-- Assume T has operation "function Empty return T;"
package G is
procedure Test(X : in out NT);
package body G is
procedure Test(X : in out NT) is
X := Empty; -- Dispatching based on X'Tag takes
-- place if actual is class-wide.
Y : NT := Empty;
-- If actual is class-wide, this raises Program_Error
-- as there is no tag provided by context.
X := Y; -- We never get this far.
type T1 is new T with null record;
package I is new G(T1'Class);
In accordance with the general rule that the actual type shall belong
to the category class
determined for the formal (see 12.5
If the formal type is nonlimited,
then so shall be the actual;
For a formal derived type, the actual
shall be in the class rooted at the ancestor subtype.
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
Ada 83 does not have unknown_discriminant_part
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.
Extensions to Ada 95
A generic formal derived type
can include progenitors (interfaces) as well as a primary ancestor. It
also may include limited to indicate that it is a limited type,
and synchronized to indicate that it is a synchronized type.
Wording Changes from Ada 95
Corrigendum: Corrected wording to define
the operations that are inherited when the ancestor of a formal type
is itself a formal type to avoid anomalies.
Added a semantic description of the meaning of
operations of an actual class-wide type, as such a type does not have
primitive operations of its own.
Added a matching rule for access subtypes that
The wording for the declaration of implicit operations
is corrected to be consistent with 7.3.1
as modified by Corrigendum 1.
We change to “determines a category”
as that is the new terminology (it avoids confusion, since not all interesting
properties form a class).
Incompatibilities With Ada 2005
Correction: Added wording
to prevent a limited type from being passed to a nonlimited formal derived
type. While this was allowed, it would break the contract for the limited
type, so hopefully no programs actually depend on that.
Extensions to Ada 2005
Formal incomplete types are
a new kind of generic formal; these can be instantiated with incomplete
types and unfrozen private types.
Wording Changes from Ada 2005
Correction: Updated the wording to acknowledge
the possibility of operations that are never declared for an actual type
but still can be used inside of a generic unit.
Correction: Fixed hole that failed to define
what happened for "=" for an untagged private type whose actual
Correction: Revised the wording for inheritance
of characteristics and operations of formal derived types to be reuse
the rules as defined for derived types; this should eliminate holes which
have plagued us with this wording (it has been changed five times since
Ada 95 was defined).
Correction: Added missing rule for the ancestors
of formal derived types. The added rule would formally be incompatible,
but since it would be impossible to instantiate any such generic, this
cannot happen outside of test suites and thus is not documented as an
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe