3.2 Types and Subtypes
is characterized by a set of values, and a set of primitive operations
which implement the fundamental aspects of its semantics.
of a given type is a run-time entity that contains (has)
a value of the type.
Term entry: type
— a defining characteristic of each object and expression of the
language, with an associated set of values, and a set of primitive operations
that implement the fundamental aspects of its semantics
Note: Types are grouped into categories. Most language-defined categories
of types are also classes of types.
Term entry: subtype
— a type together with optional constraints, null exclusions, and
predicates, which constrain the values of the type to the subset that
satisfies the implied conditions
Types are grouped into categories
There exist several language-defined
of types (see NOTES below), reflecting the similarity
of their values and primitive operations.
of types form classes
of types.] Elementary
types are those whose values are logically indivisible; composite
types are those whose values are composed of component
The formal definition of category
is found in
Term entry: class
of types — a set of types that is closed
under derivation, which means that if a given type is in the class, then
all types derived from that type are also in the class
Note: The set of types of a class share common properties, such as their
Term entry: category
of types — a set of types with one or more common properties,
such as primitive operations
Note: A category of types that is closed under derivation is also known
as a class.
Term entry: elementary
type — a type that does not have components
Term entry: composite
type — a type with components, such as an array or record
Term entry: scalar
type — either a discrete type or a real type
Term entry: access
type — a type that has values that designate aliased objects
Note: Access types correspond to “pointer types” or “reference
types” in some other languages.
Term entry: discrete
type — a type that is either an integer type or an enumeration
Term entry: real
type — a type that has values that are approximations of the
Note: Floating point and fixed point types are real types.
Term entry: integer
type — a type that represents signed or modular integers
Note: A signed integer type has a base range that includes both positive
and negative numbers, and has operations that can raise an exception
when the result is outside the base range. A modular type has a base
range whose lower bound is zero, and has operations with “wraparound”
semantics. Modular types subsume what are called “unsigned types”
in some other languages.
Term entry: enumeration
type — a type defined by an enumeration of its values, which
can be denoted by identifiers or character literals
Term entry: character
type — an enumeration type whose values include characters
Term entry: record
type — a composite type consisting of zero or more named components,
possibly of different types
Term entry: record
extension — a type that extends another type optionally with
Term entry: array
type — a composite type whose components are all of the same
Term entry: task
type — a composite type used to represent active entities which
execute concurrently and that can communicate via queued task entries
Note: The top-level task of a partition is called the environment task.
Term entry: protected
type — a composite type whose components are accessible only
through one of its protected operations, which synchronize concurrent
access by multiple tasks
Term entry: private
type — a view of a type that reveals only some of its properties
Note: The remaining properties are provided by the full view given elsewhere.
Private types can be used for defining abstractions that hide unnecessary
details from their clients.
Term entry: private
extension — a type that extends another type, with the additional
properties hidden from its clients
Term entry: incomplete
type — a view of a type that reveals only a few of its properties
Note 1: The remaining properties are provided by the full view given
Note 2: Incomplete types can be used for defining recursive data structures.
The elementary types are the
) and the access
types (whose values provide access to objects or subprograms).
types are either integer
types or are defined by enumeration of
their values (enumeration
are either floating point
types or fixed point
The composite types are the record
types, record extensions
types, and protected
be multiple views of a type with varying sets of operations. [An incomplete
type represents an incomplete view (see 3.10.1
of a type with a very restricted usage, providing support for recursive
data structures. A private
type or private extension
a partial view (see 7.3
) of a type, providing
support for data abstraction. The full view (see 3.2.1
of a type represents its complete definition.] An incomplete or partial
view is considered a composite type[, even if the full view is not].
The real definitions of the views are in the referenced subclauses.
Certain composite types (and views thereof) have
special components called discriminants
whose values affect the
presence, constraints, or initialization of other components. Discriminants
can be thought of as parameters of the type.
The term subcomponent
is used in this Reference
Manual in place of the term component to indicate either a component,
or a component of another subcomponent. Where other subcomponents are
excluded, the term component is used instead.
of an object or value is used to mean the whole object
or value, or any set of its subcomponents. The terms component, subcomponent,
and part are also applied to a type meaning the component, subcomponent,
or part of objects and values of the type.
Discussion: The definition of “part”
here is designed to simplify rules elsewhere. By design, the intuitive
meaning of “part” will convey the correct result to the casual
reader, while this formalistic definition will answer the concern of
We use the term “part” when talking
about the parent part, ancestor part, or extension part of a type extension.
In contexts such as these, the part might represent an empty set of subcomponents
(e.g. in a null record extension, or a nonnull extension of a null record).
We also use “part” when specifying rules such as those that
apply to an object with a “controlled part” meaning that
it applies if the object as a whole is controlled, or any subcomponent
The set of possible values for an object of a given
type can be subjected to a condition that is called a constraint
(the case of a null constraint
that specifies no restriction is also included)[; the rules for which
values satisfy a given kind of constraint are given in 3.5
The set of possible values for an object of an access type can also be
subjected to a condition that excludes the null value (see 3.10
“Null constraint” includes the cases
of no explicit constraint, as well as unknown discriminants and unconstrained
array type declarations (which are explicit ways to declare no constraint).
of a given type is a combination
of the type, a constraint on values of the type, and certain attributes
specific to the subtype. The given type is called the type of the
Similarly, the associated
constraint is called the constraint of the subtype
The set of values of a subtype consists of the values
of its type that satisfy its constraint and any exclusion of the null
Such values belong
to the subtype.
The other values of the type
are outside the subtype.
Discussion: We make a strong distinction
between a type and its subtypes. In particular, a type is not
a subtype of itself. There is no constraint associated with a type (not
even a null one), and type-related attributes are distinct from subtype-specific
Discussion: We no longer use the term
"base type." All types were "base types" anyway in
Ada 83, so the term was redundant, and occasionally confusing. In the
RM95 we say simply "the type of the subtype" instead
of "the base type of the subtype."
Ramification: The value subset for a
subtype might be empty, and need not be a proper subset.
To be honest:
Any name of a category of types (such as “discrete”, “real”,
or “limited”) is also used to qualify its subtypes, as well
as its objects, values, declarations, and definitions, such as an “integer
type declaration” or an “integer value”. In addition,
if a term such as “parent subtype” or “index subtype”
is defined, then the corresponding term for the type of the subtype is
“parent type” or “index type”.
Discussion: We use these corresponding
terms without explicitly defining them, when the meaning is obvious.
subtype is called an unconstrained
subtype if its type has unknown
discriminants, or if its type allows range, index, or discriminant constraints,
but the subtype does not impose such a constraint; otherwise, the subtype
is called a constrained
subtype (since it has no unconstrained
Discussion: In an earlier version of
Ada 9X, "constrained" meant "has a nonnull constraint."
However, we changed to this definition since we kept having to special
case composite non-array/nondiscriminated types. It also corresponds
better to the (now obsolescent) attribute 'Constrained.
For scalar types, “constrained”
means “has a nonnull constraint”. For composite types, in
implementation terms, “constrained” means that the size of
all objects of the subtype is the same, assuming a typical implementation
Class-wide subtypes are always unconstrained.
Any set of types can be called a “category” of types, and
any set of types that is closed under derivation (see 3.4
can be called a “class” of types. However, only certain categories
and classes are used in the description of the rules of the language
— generally those that have their own particular set of primitive
operations (see 3.2.3
), or that correspond
to a set of types that are matched by a given kind of generic formal
type (see 12.5
are examples of “interesting” language-defined classes
elementary, scalar, discrete, enumeration, character, boolean, integer,
signed integer, modular, real, floating point, fixed point, ordinary
fixed point, decimal fixed point, numeric, access, access-to-object,
access-to-subprogram, composite, array, string, (untagged) record, tagged,
task, protected, nonlimited. Special syntax is provided to define types
in each of these classes. In addition to these classes, the following
are examples of “interesting” language-defined categories
abstract, incomplete, interface, limited, private,
is a run-time entity with a given type which can be assigned to an object
of an appropriate subtype of the type.
is a program entity that operates on zero or more operands to produce
an effect, or yield a result, or both.
Note that a type's category (and class) depends on the place of the reference
— a private type is composite outside and possibly elementary inside.
It's really the view
that is elementary or composite. Note that
although private types are composite, there are some properties that
depend on the corresponding full view — for example, parameter
passing modes, and the constraint checks that apply in various places.
Every property of types forms a category, but not every property of types
represents a class. For example, the set of all abstract types does not
form a class, because this set is not closed under derivation. Similarly,
the set of all interface types does not form a class.
The set of limited types does not form a class (since nonlimited types
can inherit from limited interfaces), but the set of nonlimited types
does. The set of tagged record types and the set of tagged private types
do not form a class (because each of them can be extended to create a
type of the other category); that implies that the set of record types
and the set of private types also do not form a class (even though untagged
record types and untagged private types do form a class). In all of these
cases, we can talk about the category of the type; for instance, we can
talk about the “category of limited types”.
Normatively, the language-defined classes
are those that are defined
to be inherited on derivation by 3.4
properties either aren't interesting or form categories, not classes.
These language-defined categories are organized like this:
ordinary fixed point
decimal fixed point
tagged (including interfaces)
nonlimited tagged record
limited tagged record
There are other categories, such as “numeric” and “discriminated”,
which represent other categorization dimensions, but do not fit into
the above strictly hierarchical picture.
Note that this is also true for some categories mentioned in the chart.
The category “task” includes both untagged tasks and tagged
tasks. Similarly for “protected”, “limited”,
and “nonlimited” (note that limited and nonlimited are not
shown for untagged composite types).
Wording Changes from Ada 83
This subclause now precedes the subclauses on objects and named numbers,
to cut down on the number of forward references.
We have dropped the term "base type"
in favor of simply "type" (all types in Ada 83 were "base
types" so it wasn't clear when it was appropriate/necessary to say
"base type"). Given a subtype S of a type T, we call T the
"type of the subtype S."
Wording Changes from Ada 95
Added a mention of null exclusions when we're talking about constraints
(these are not constraints, but they are similar).
Defined an interface type to be a composite type.
Revised the wording so that it is clear that an incomplete view is similar
to a partial view in terms of the language.
Added a definition of component of a type, subcomponent of a type, and
part of a type. These are commonly used in the standard, but they were
not previously defined.
Reworded most of this subclause to use category rather than class, since
so many interesting properties are not, strictly speaking, classes. Moreover,
there was no normative description of exactly which properties formed
classes, and which did not. The real definition of class, along with
a list of properties, is now in 3.4
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe