12.5.1 Formal Private and Derived Types
{
AI95-00442-01}
{
AI05-0213-1}
{
AI12-0445-1}
[In its most general form, the category determined for a formal private
type is all types, but the category can be restricted to only nonlimited
types or to only tagged types. 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 can be incompletely defined,
and not ready to be frozen (see
13.14). The
category determined for a formal derived type is the derivation class
rooted at the ancestor type.]
Proof: {
AI95-00442-01}
{
AI05-0213-1}
The first two rules are given normatively below, and the third rule is
given normatively in
12.5; they are repeated
here to give a capsule summary of what this subclause is about.
Ramification: {
AI05-0213-1}
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 its completion.
Syntax
formal_private_type_definition ::= [[
abstract]
tagged] [
limited]
private
Legality Rules
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.
{
AI95-00401-01}
{
AI95-00419-01}
{
AI95-00443-01}
{
AI05-0237-1}
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, an
interface_list
or the optional reserved words
abstract or
synchronized
shall 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.
{
AI95-00419-01}
{
AI05-0005-1}
We require the ancestor type to be limited when
limited appears
so that we avoid oddities 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.
{
AI95-00443-01}
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.
{
AI95-00251-01}
{
AI95-00401-01}
{
AI95-00443-01}
{
AI05-0087-1}
{
AI12-0036-1}
{
AI12-0442-1}
The actual type for a formal derived type shall be a descendant of [the
ancestor type and] every progenitor of the formal type. The actual type
for a formal derived type shall be tagged if and only if the formal derived
type is a private extension. 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.
Discussion: {
AI05-0005-1}
For a nonformal 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 noninterface type
will be enforced. This is consistent with the “no hidden interfaces”
rule also applying only to nonformal private extensions, as well as the
rule that a limited nonformal 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.
{
AI05-0087-1}
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.
{
AI12-0036-1}
{
AI12-0005-1}
If we allowed actual types whose kind differs from that of the formal
derived type, we could allow type conversions that would not be allowed
outside of the generic. That would be particularly problematical if the
actual is a tagged type with extension components; we could have created
an object of the type that is missing those components by converting
from the ancestor type to a formal derived type that is not an extension.
{
AI05-0213-1}
{
AI12-0442-1}
If a formal private or derived subtype is definite, then the actual subtype
shall also be definite. If the formal type is nonlimited, the actual
type shall be nonlimited.
Ramification: On the other hand, for
an indefinite formal subtype, the actual can be either definite or indefinite.
Discussion: {
AI12-0442-1}
The rule about nonlimited formals applies to both private and derived
formal types.
{
AI05-0213-1}
A
formal_incomplete_type_declaration
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
3.10.1.]
{
AI12-0351-1}
For a generic formal derived type with no
discriminant_part,
the actual subtype shall be statically compatible with the ancestor subtype.
Furthermore:
{
AI12-0351-1}
If the ancestor subtype is constrained, the actual subtype shall be constrained;
Ramification: {
AI12-0351-1}
In other words, any constraint on the ancestor subtype is considered
part of the “contract”. Predicates are also considered part
of the contract for
any subtype, via the static compatibility
requirement.
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.
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 runtime 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.
{
AI95-00231-01}
If the ancestor subtype is an access subtype, the actual subtype shall
exclude null if and only if the ancestor subtype excludes null.
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
of discriminants.
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.
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.
{
AI12-0095-1}
When enforcing Legality Rules, for the purposes of determining within
a generic body whether a type is unconstrained in any partial view, a
discriminated subtype is considered to have a constrained partial view
if it is a descendant of an untagged generic formal private or derived
type.
Static Semantics
{
AI95-00442-01}
The category determined for a formal private type is as follows:
Type Definition Determined Category
limited private the category of all types
private the category of all nonlimited types
tagged limited private the category of all tagged types
tagged private the category of all nonlimited tagged types
[The presence of the reserved word abstract
determines whether the actual type may be abstract.]
{
AI05-0213-1}
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.]
{
AI95-00233-01}
{
AI05-0110-1}
For a formal derived type, the characteristics (including components,
but excluding discriminants if there is a new
discriminant_part),
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 a derived type are determined by those
of its parent type and its progenitor types (see
3.4
and
7.3.1).
{
8652/0038}
{
AI95-00202}
{
AI95-00233-01}
{
AI95-00401-01}
{
AI05-0029-1}
{
AI05-0110-1}
In an instance, the copy of an 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. When 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.]
Ramification: {
AI95-00401-01}
{
AI05-0239-1}
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 (or progenitor type, for subprograms inherited from an
interface type).
To be honest: {
AI12-0030-1}
The availability of stream attributes is not formally a characteristic
of a type, but it is still determined by the ancestor type for a formal
derived type in the same way as the characteristics are. Availability
is rechecked in the instance specification.
{
AI12-0419-1}
In an instance, the implicitly composed and additive aspects (see
13.1.1)
of a formal type are those of the actual; for a nonoverridable aspect,
a formal derived type inherits the aspect if the ancestor or any progenitor
has the aspect, according to the rules given in
13.1.
For a
prefix
S that denotes a formal indefinite subtype, the following attribute is
defined:
S'Definite
{
AI05-0264-1}
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: {
AI95-00114-01}
{
AI12-0005-1}
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 obsolescent.
Dynamic Semantics
{
AI95-00158-01}
{
AI05-0071-1}
In the case where a formal type has unknown discriminants, and the actual
type is a class-wide type
T'Class:
{
AI95-00158-01}
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.
{
AI95-00158-01}
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.
Discussion: As it states in
6.3.1,
the convention of an inherited subprogram of a generic formal tagged
type with unknown discriminants is intrinsic.
In 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:
generic
type NT(<>) is new T with private;
-- Assume T has operation "function Empty return T;"
package G is
procedure Test(X : in out NT);
end G;
package body G is
procedure Test(X : in out NT) is
begin
X := Empty; -- Dispatching based on X'Tag takes
-- place if actual is class-wide.
declare
Y : NT := Empty;
-- If actual is class-wide, this raises Program_Error
-- as there is no tag provided by context.
begin
X := Y; -- We never get this far.
end;
end Test;
end G;
type T1 is new T with null record;
package I is new G(T1'Class);
NOTE 1 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 nonabstract actual to an abstract formal — abstract
on the formal indicates that the actual might be abstract.
NOTE 2 {
AI12-0447-1}
If the formal has a
discriminant_part,
the actual can be either definite or indefinite. Otherwise, the actual
can only be definite.
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 runtime check to a compile-time check.
Extensions to Ada 95
{
AI95-00251-01}
{
AI95-00401-01}
{
AI95-00419-01}
{
AI95-00443-01}
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
{
8652/0038}
{
AI95-00202-01}
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.
{
AI95-00158-01}
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.
{
AI95-00231-01}
Added a matching rule for access subtypes that exclude null.
{
AI95-00233-01}
The wording for the declaration of implicit operations is corrected to
be consistent with
7.3.1 as modified by Corrigendum
1.
{
AI95-00442-01}
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
{
AI05-0087-1}
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
{
AI05-0213-1}
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
{
AI05-0029-1}
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.
{
AI05-0071-1}
Correction: Fixed hole that failed to define what happened for
"=" for an untagged private type whose actual is class-wide.
{
AI05-0110-1}
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 in the wording which have
plagued us since Ada 95 was defined (it has been "corrected"
four previous times).
{
AI05-0237-1}
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 incompatibility.
Incompatibilities With Ada 2012
{
AI12-0036-1}
Corrigendum: Added a requirement that a tagged
type only match a formal derived type that is a private extension. This
is necessary to prevent type conversions that would not be allowed outside
of the generic. We expect that this will be rare, as it only can happen
if the formal derived type does not accurately describe the actual type;
in most such cases, extension will be desired and a private extension
used so that is allowed.
{
AI12-0351-1}
Correction: The predicates of an ancestor subtype are considered
part of the contract for a formal derived type, even if the ancestor
subtype is unconstrained. This means, for instance, if the ancestor subtype
is a subtype of Float with a predicate, then an actual subtype with a
different predicate is illegal in Ada 2022 while it would have been allowed
in Ada 2012. Cases like this are quite unlikely and will be detected
at compile-time if they occur.
Wording Changes from Ada 2012
{
AI12-0095-1}
Corrigendum: The assume the worst rule for determining within
a generic body whether a type is unconstrained in any partial view was
moved here. While AI05-0041-1 added it to
3.10.2,
it's also needed (at least) in
4.6 and
6.4.1.
Thus, it was moved here so that it applies generally.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe