3.4.1 Derivation Classes
In addition to the various language-defined classes 
of types, types can be grouped into derivation classes. 
Static Semantics
{
AI95-00251-01} 
{
AI95-00401-01} 
A derived type is 
derived from its parent 
type 
directly; it is derived 
indirectly from any type from 
which its parent type is derived. A derived type, interface type, type 
extension, task type, protected type, or formal derived type is also 
derived from every ancestor of each of its progenitor types, if any. 
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). 
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. 
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. 
{
AI95-00230-01} 
{
AI12-0437-1} 
Every type is one of a 
specific type, a 
class-wide type, 
or a 
universal type. 
A specific type is one 
defined by a 
type_declaration, 
a 
formal_type_declaration, 
or a full type definition embedded in another construct. Class-wide and 
universal types are implicitly defined, to act as representatives for 
an entire class of types, as follows: 
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. 
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).
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. 
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. 
 
{
AI22-0027-1} 
When a language rule references a given primitive 
operation of a type, in the case of a class-wide type T'Class, 
this is equivalent to 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.
Universal types are defined for [(and belong to)] the integer, real, 
fixed point, and access classes, and are referred to in this document 
as respectively, 
universal_integer, 
universal_real, 
universal_fixed, 
and 
universal_access. 
These are analogous to class-wide types for these language-defined elementary 
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, 
or the literal 
null) is “universal” in that it is 
acceptable where some particular type in the class is expected (see 
8.6).
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. 
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.
{
AI95-00230-01} 
We considered defining class-wide or perhaps universal types for all 
derivation classes, not just tagged classes and these four elementary 
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.
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. 
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. 
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.
{
AI12-0325-1} 
A class-wide or universal type is said to 
cover 
all of the types in its class. In addition, 
universal_integer 
covers a type that has a specified Integer_Literal aspect, while 
universal_real 
covers a type that has a specified Real_Literal aspect (see 
4.2.1). 
A specific type covers only itself.
{
AI95-00230-01} 
{
AI95-00251-01} 
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 numeric universal types 
are defined to be descendants of the root types of their classes. 
If 
a type 
T2 is a descendant of a type 
T1, then 
T1 
is called an 
ancestor of 
T2. 
An 
ultimate ancestor of a type is an ancestor of that type that is 
not itself a descendant of any other type. Every untagged type has a 
unique ultimate ancestor. 
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.
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. 
Discussion: 
The terms root, parent, ancestor, and ultimate ancestor are all related. 
For example: 
{
AI95-00251-01} 
Each type has at most one parent, and one or more ancestor types; each 
untagged 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.
A class of types has at most one root type; 
a derivation class has exactly one root type.
The root of a class is an ancestor of all 
of the types in the class (including itself).
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. 
Term entry: ancestor of a type 
— type itself or, in the case of a type derived from other types, 
its parent type or one of its progenitor types or one of their ancestors
Note: Ancestor and descendant are inverse relationships.
Term entry: descendant of a type 
— type itself or a type derived (directly or indirectly) from it
Note: Descendant and ancestor are inverse relationships.
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.
NOTE   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 
1 + 4 < 7
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. 
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. 
Wording Changes from Ada 95
{
AI95-00230-01} 
Updated the wording to define the 
universal_access type. This 
was defined to make 
null for anonymous access types sensible.
{
AI95-00251-01} 
{
AI95-00401-01} 
The definitions of ancestors and descendants were updated to allow multiple 
ancestors (necessary to support interfaces). 
Wording Changes from Ada 2012
{
AI12-0325-1} 
Updated the wording to say that universal types cover the types with 
the appropriate user-defined literal. 
Wording Changes from Ada 2022
{
AI22-0027-1} 
Corrigendum: Moved the description of primitive 
operations of class-wide types here from 12.5.1. 
No semantic change is intended. 
 Ada 2005 and 2012 Editions sponsored in part by Ada-Europe
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe