Contents Index Previous Next
3.4.1 Derivation Classes
1
In addition to the various language-defined classes
of types, types can be grouped into derivation classes.
Static Semantics
2
{derived from (directly or indirectly)}
A derived type is
derived from its parent
type
directly; it is derived
indirectly from any type from
which its parent type is derived.
{derivation class
(for a type)} {root type
(of a class)} {rooted
at a type} The derivation class of types
for a type
T (also called the class
rooted at
T)
is the set consisting of
T (the
root type of the class)
and all types derived from
T (directly or indirectly) plus any
associated universal or class-wide types (defined below).
2.a
Discussion: Note that the
definition of ``derived from'' is a recursive definition. We don't define
a root type for all interesting language-defined classes, though presumably
we could.
2.b
To be honest: By the class-wide
type ``associated'' with a type T, we mean the type T'Class.
Similarly, the universal type associated with root_integer, root_real,
and root_fixed are universal_integer, universal_real,
and universal_fixed, respectively.
3
Every type is either a
specific type, a
class-wide type, or a
universal type.
{specific
type} A specific type is one defined by
a
type_declaration, a
formal_type_declaration,
or a full type definition embedded in a declaration for an object. Class-wide
and universal types are implicitly defined, to act as representatives
for an entire class of types, as follows:
3.a
To be honest: The root
types root_integer, root_real, and root_fixed are
also specific types. They are declared in the specification of package
Standard.
4
- {class-wide type} Class-wide
types
- Class-wide types are defined for [(and belong to)] each
derivation class rooted at a tagged type (see 3.9).
Given a subtype S of a tagged type T, S'Class is the subtype_mark
for a corresponding subtype of the tagged class-wide type T'Class.
Such types are called ``class-wide'' because when a formal parameter is defined
to be of a class-wide type T'Class, an actual parameter of any type
in the derivation class rooted at T is acceptable (see 8.6).
5
- {first subtype} The
set of values for a class-wide type T'Class is the discriminated union
of the set of values of each specific type in the derivation class rooted
at T (the tag acts as the implicit discriminant -- see 3.9).
Class-wide types have no primitive subprograms of their own. However, as explained
in 3.9.2, operands of a class-wide type T'Class
can be used as part of a dispatching call on a primitive subprogram of the
type T. The only components [(including discriminants)] of T'Class
that are visible are those of T. If S is a first subtype, then S'Class
is a first subtype.
5.a
Reason: We want S'Class
to be a first subtype when S is, so that an attribute_definition_clause
like ``for S'Class'Output use ...;'' will be legal.
6
- {universal type} Universal
types
- Universal types are defined for [(and belong to)] the integer,
real, and fixed point classes, and are referred to in this standard as respectively,
universal_integer, universal_real, and universal_fixed.
These are analogous to class-wide types for these language-defined numeric
classes. As with class-wide types, if a formal parameter is of a universal
type, then an actual parameter of any type in the corresponding class is acceptable.
In addition, a value of a universal type (including an integer or real numeric_literal)
is ``universal'' in that it is acceptable where some particular type in the
class is expected (see 8.6).
7
- The set of values of a universal type is the undiscriminated
union of the set of values possible for any definable type in the associated
class. Like class-wide types, universal types have no primitive subprograms
of their own. However, their ``universality'' allows them to be used
as operands with the primitive subprograms of any type in the corresponding
class.
7.a
Discussion: A class-wide
type is only class-wide in one direction, from specific to class-wide,
whereas a universal type is class-wide (universal) in both directions,
from specific to universal and back.
7.b
We considered defining class-wide
or perhaps universal types for all derivation classes, not just tagged
classes and these three numeric classes. However, this was felt to overly
weaken the strong-typing model in some situations. Tagged types preserve
strong type distinctions thanks to the run-time tag. Class-wide or universal
types for untagged types would weaken the compile-time type distinctions
without providing a compensating run-time-checkable distinction.
7.c
We considered defining standard
names for the universal numeric types so they could be used in formal
parameter specifications. However, this was felt to impose an undue implementation
burden for some implementations.
7.d
To be honest: Formally,
the set of values of a universal type is actually a copy of the
undiscriminated union of the values of the types in its class. This is
because we want each value to have exactly one type, with explicit or
implicit conversion needed to go between types. An alternative, consistent
model would be to associate a class, rather than a particular type, with
a value, even though any given expression would have a particular type.
In that case, implicit type conversions would not generally need to change
the value, although an associated subtype conversion might need to.
8
{root_integer [partial]}
{root_real [partial]}
The integer and real numeric classes each have a
specific root type in addition to their universal type, named respectively
root_integer and
root_real.
9
{cover (a type)} A
class-wide or universal type is said to
cover all of the types
in its class. A specific type covers only itself.
10
{descendant (of a type)}
A specific type
T2 is defined to be a
descendant
of a type
T1 if
T2 is the same as
T1, or if
T2
is derived (directly or indirectly) from
T1. A class-wide type
T2'Class is defined to be a descendant of type
T1 if
T2
is a descendant of
T1. Similarly, the universal types are defined
to be descendants of the root types of their classes.
{ancestor
(of a type)} If a type
T2 is a
descendant of a type
T1, then
T1 is called an
ancestor
of
T2.
{ultimate ancestor (of a type)}
{ancestor (ultimate)}
The
ultimate ancestor of a type is the ancestor
of the type that is not a descendant of any other type.
10.a
Ramification: A specific
type is a descendant of itself. Class-wide types are considered descendants
of the corresponding specific type, and do not have any descendants of
their own.
10.b
A specific type is an ancestor
of itself. The root of a derivation class is an ancestor of all types
in the class, including any class-wide types in the class.
10.c
Discussion:
The terms root, parent, ancestor, and ultimate ancestor are all related.
For example:
10.d
- Each type has at most one parent, and one or more ancestor
types; each type has exactly one ultimate ancestor. In Ada 83, the term
``parent type'' was sometimes used more generally to include any ancestor
type (e.g. RM83-9.4(14)). In Ada 95, we restrict parent to mean the immediate
ancestor.
10.e
- A class of types has at most one root type; a derivation
class has exactly one root type.
10.f
- The root of a class is an ancestor of all of the types
in the class (including itself).
10.g
- The type root_integer is the root of the integer
class, and is the ultimate ancestor of all integer types. A similar statement
applies to root_real.
11
{inherited (from an ancestor
type)} An inherited component [(including
an inherited discriminant)] of a derived type is inherited
from
a given ancestor of the type if the corresponding component was inherited
by each derived type in the chain of derivations going back to the given
ancestor.
12
18 Because operands of a universal
type are acceptable to the predefined operators of any type in their class,
ambiguity can result. For universal_integer and universal_real,
this potential ambiguity is resolved by giving a preference (see 8.6)
to the predefined operators of the corresponding root types (root_integer
and root_real, respectively). Hence, in an apparently ambiguous expression
like
13
1 + 4 < 7
14
where each of the literals is of type
universal_integer, the predefined operators of root_integer
will be preferred over those of other specific integer types, thereby
resolving the ambiguity.
14.a
Ramification: Except for
this preference, a root numeric type is essentially like any other specific
type in the associated numeric class. In particular, the result of a
predefined operator of a root numeric type is not ``universal'' (implicitly
convertible) even if both operands were.
Contents Index Previous Next Legal