[Home] [Prev] [Next] [Index]

3.2 Types and Subtypes

3.2 Types and Subtypes

Static Semantics

1
A type is characterized by a set of values, and a set of primitive operations which implement the fundamental aspects of its semantics. An object of a given type is a run-time entity that contains (has) a value of the type.

1.a
Glossary entry: Each object has a type. A type has an associated set of values, and a set of primitive operations which implement the fundamental aspects of its semantics. Types are grouped into classes. The types of a given class share a set of primitive operations. Classes are closed under derivation; that is, if a type is in a class, then all of its derivatives are in that class.

1.b
Glossary entry: A subtype is a type together with a constraint, which constrains the values of the subtype to satisfy a certain condition. The values of a subtype are a subset of the values of its type.

2
Types are grouped into classes of types, reflecting the similarity of their values and primitive operations. There exist several language-defined classes of types (see NOTES below). Elementary types are those whose values are logically indivisible; composite types are those whose values are composed of component values.

2.a
Glossary entry: A class is 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. The set of types of a class share common properties, such as their primitive operations.

2.b
Glossary entry: An elementary type does not have components.

2.c
Glossary entry: A composite type has components.

2.d
Glossary entry: A scalar type is either a discrete type or a real type.

2.e
Glossary entry: An access type has values that designate aliased objects. Access types correspond to "pointer types" or "reference types" in some other languages.

2.f
Glossary entry: A discrete type is either an integer type or an enumeration type. Discrete types may be used, for example, in case_statements and as array indices.

2.g
Glossary entry: A real type has values that are approximations of the real numbers. Floating point and fixed point types are real types.

2.h
Glossary entry: Integer types comprise the signed integer types and the modular types. A signed integer type has a base range that includes both positive and negative numbers, and has operations that may 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.

2.i
Glossary entry: An enumeration type is defined by an enumeration of its values, which may be named by identifiers or character literals.

2.j
Glossary entry: A character type is an enumeration type whose values include characters.

2.k
Glossary entry: A record type is a composite type consisting of zero or more named components, possibly of different types.

2.l
Glossary entry: A record extension is a type that extends another type by adding additional components.

2.m
Glossary entry: An array type is a composite type whose components are all of the same type.  Components are selected by indexing.

2.n
Glossary entry: A task type is a composite type whose values are tasks, which are active entities that may execute concurrently with other tasks. The top-level task of a partition is called the environment task.

2.o
Glossary entry: A protected type is a composite type whose components are protected from concurrent access by multiple tasks.

2.p
Glossary entry: A private type is a partial view of a type whose full view is hidden from its clients.

2.q
Glossary entry: A private extension is like a record extension, except that the components of the extension part are hidden from its clients.

3
The elementary types are the scalar types (discrete and real) and the access types (whose values provide access to objects or subprograms). Discrete types are either integer types or are defined by enumeration of their values (enumeration types). Real types are either floating point types or fixed point types.

4
The composite types are the record types, record extensions, array types, task types, and protected types. A private type or private extension represents a partial view (see 7.3) of a type, providing support for data abstraction. A partial view is a composite type.

4.a
To be honest: The set of all record types do not form a class (because tagged record types can have private extensions), though the set of untagged record types do. In any case, what record types had in common in Ada 83 (component selection) is now a property of the composite class, since all composite types (other than array types) can have discriminants. Similarly, the set of all private types do not form a class (because tagged private types can have record extensions), though the set of untagged private types do. Nevertheless, the set of untagged private types is not particularly "interesting" - more interesting is the set of all nonlimited types, since that is what a generic formal (nonlimited) private type matches.

5
Certain composite types (and partial 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.

6
The term subcomponent is used in this International Standard 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. Similarly, a part of an object or value is used to mean the whole object or value, or any set of its subcomponents.

6.a
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 the compiler-writer.

6.b
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 is.

7
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 for range_constraints, 3.6.1 for index_constraints, and 3.7.1 for discriminant_constraints].

8
A subtype 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 subtype. 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. Such values belong to the subtype.

8.a
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 attributes.

8.b
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 RM9X we say simply "the type of the subtype" instead of "the base type of the subtype."

8.c
Ramification: The value subset for a subtype might be empty, and need not be a proper subset.

8.d
To be honest: Any name of a class of types (such as "discrete" or "real"), or other category of types (such as "limited" or "incomplete") 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."

8.e
Discussion:  We use these corresponding terms without explicitly defining them, when the meaning is obvious.

9
A 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 characteristics).

9.a
Discussion:  In an earlier version of Ada 9X, "constrained" meant "has a non-null constraint."  However, we changed to this definition since we kept having to special case composite non-array/non-discriminated types.  It also corresponds better to the (now obsolescent) attribute 'Constrained.

9.b
For scalar types, "constrained" means "has a non-null 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 model.

9.c
Class-wide subtypes are always unconstrained.

NOTES

10 2
Any set of types that is closed under derivation (see 3.4) can be called a "class" of types.  However, only certain 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). The following 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.

10.a
Discussion:  A value is a run-time entity with a given type which can be assigned to an object of an appropriate subtype of the type. An operation is a program entity that operates on zero or more operands to produce an effect, or yield a result, or both.

10.b
Ramification: Note that a type's 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.

10.c
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.

10.d
The set of limited types forms a class in the sense that it is closed under derivation, but the more interesting class, from the point of generic formal type matching, is the set of all types, limited and nonlimited, since that is what matches a generic formal "limited" private type. Note also that a limited type can "become nonlimited" under certain circumstances, which makes "limited" somewhat problematic as a class of types.

11
These language-defined classes are organized like this:

all types
elementary
scalar
discrete
enumeration
character
boolean
other enumeration
integer
signed integer
modular integer
real
floating point
fixed point
ordinary fixed point
decimal fixed point
access
access-to-object
access-to-subprogram
composite
array
string
other array
untagged record
tagged
task
protected
13
The classes "numeric" and "nonlimited" represent other classification dimensions and do not fit into the above strictly hierarchical picture.

Wording Changes From Ada 83

13.a
This clause and its subclauses now precede the clause and subclauses on objects and named numbers, to cut down on the number of forward references.

13.b
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."

3.2.1 Type Declarations

1
A type_declaration declares a type and its first subtype.

Syntax

2
type_declaration ::=  full_type_declaration
   | incomplete_type_declaration
   | private_type_declaration
   | private_extension_declaration

3
full_type_declaration ::=
     type defining_identifier [known_discriminant_part] is type_definition;
   | task_type_declaration
   | protected_type_declaration

4
type_definition ::=
     enumeration_type_definition | integer_type_definition
   | real_type_definition     | array_type_definition
   | record_type_definition   | access_type_definition
   | derived_type_definition

Legality Rules

5
A given type shall not have a subcomponent whose type is the given type itself.

Static Semantics

6
The defining_identifier of a type_declaration denotes the first subtype of the type. The known_discriminant_part, if any, defines the discriminants of the type (see 3.7, "Discriminants"). The remainder of the type_declaration defines the remaining characteristics of (the view of) the type.

7
A type defined by a type_declaration is a named type; such a type has one or more nameable subtypes. Certain other forms of declaration also include type definitions as part of the declaration for an object (including a parameter or a discriminant).  The type defined by such a declaration is anonymous - it has no nameable subtypes. For explanatory purposes, this International Standard sometimes refers to an anonymous type by a pseudo-name, written in italics, and uses such pseudo-names at places where the syntax normally requires an identifier.  For a named type whose first subtype is T, this International Standard sometimes refers to the type of T as simply "the type T."

7.a
Ramification: The only user-defined types that can be anonymous in the above sense are array, access, task, and protected types. An anonymous array, task, or protected type can be defined as part of an object_declaration. An anonymous access type can be defined as part of a parameter or discriminant specification.

8
A named type that is declared by a full_type_declaration, or an anonymous type that is defined as part of declaring an object of the type, is called a full type. The type_definition, task_definition, protected_definition, or access_definition that defines a full type is called a full type definition. [Types declared by other forms of type_declaration are not separate types; they are partial or incomplete views of some full type.]

8.a
To be honest: Class-wide, universal, and root numeric types are full types.

9
The definition of a type implicitly declares certain predefined operators that operate on the type, according to what classes the type belongs, as specified in 4.5, "Operators and Expression Evaluation".

9.a
Discussion:  We no longer talk about the implicit declaration of basic operations. These are treated like an if_statement - they don't need to be declared, but are still applicable to only certain classes of types.

10
The predefined types [(for example the types Boolean, Wide_Character, Integer, root_integer, and universal_integer)] are the types that are defined in [a predefined library package called] Standard[; this package also includes the [(implicit)] declarations of their predefined operators]. [The package Standard is described in A.1.]

10.a
Ramification: We use the term "predefined" to refer to entities declared in the visible part of Standard, to implicitly declared operators of a type whose semantics are defined by the language, to Standard itself, and to the "predefined environment". We do not use this term to refer to library packages other than Standard. For example Text_IO is a language-defined package, not a predefined package, and Text_IO.Put_Line is not a predefined operation.

Dynamic Semantics

11
The elaboration of a full_type_declaration consists of the elaboration of the full type definition. Each elaboration of a full type definition creates a distinct type and its first subtype.

11.a
Reason: The creation is associated with the type definition, rather than the type declaration, because there are types that are created by full type definitions that are not immediately contained within a type declaration (e.g. an array object declaration, a singleton task declaration, etc.).

11.b
Ramification: Any implicit declarations that occur immediately following the full type definition are elaborated where they (implicitly) occur.

Examples

12
Examples of type definitions:

13
(White, Red, Yellow, Green, Blue, Brown, Black)
range 1 .. 72
array(1 .. 10) of Integer

14
Examples of type declarations:

15
type Color  is (White, Red, Yellow, Green, Blue, Brown, Black);
type Column is range 1 .. 72;
type Table  is array(1 .. 10) of Integer;

NOTES

16 3
Each of the above examples declares a named type.  The identifier given denotes the first subtype of the type.  Other named subtypes of the type can be declared with subtype_declarations (see 3.2.2).  Although names do not directly denote types, a phrase like "the type Column" is sometimes used in this International Standard to refer to the type of Column, where Column denotes the first subtype of the type.  For an example of the definition of an anonymous type, see the declaration of the array Color_Table in 3.3.1; its type is anonymous - it has no nameable subtypes.

Wording Changes From Ada 83

16.a
The syntactic category full_type_declaration now includes task and protected type declarations.

16.b
We have generalized the concept of first-named subtype (now called simply "first subtype") to cover all kinds of types, for uniformity of description elsewhere. RM83 defined first-named subtype in Section 13. We define first subtype here, because it is now a more fundamental concept. We renamed the term, because in Ada 9X some first subtypes have no name.

16.c
We no longer elaborate discriminant_parts, because there is nothing to do, and it was complex to say that you only wanted to elaborate it once for a private or incomplete type.  This is also consistent with the fact that subprogram specifications are not elaborated (neither in Ada 83 nor in Ada 9X).  Note, however, that an access_definition appearing in a discriminant_part is elaborated when an object with such a discriminant is created.

3.2.2 Subtype Declarations

1
A subtype_declaration declares a subtype of some previously declared type, as defined by a subtype_indication.

Syntax

2
subtype_declaration ::=
   subtype defining_identifier is subtype_indication;

3
subtype_indication ::=  subtype_mark [constraint]

4
subtype_mark ::= subtype_name

4.a
Ramification: Note that name includes attribute_reference; thus, S'Base can be used as a subtype_mark.

4.b
Reason: We considered changing subtype_mark to subtype_name. However, existing users are used to the word "mark," so we're keeping it.

5
constraint ::= scalar_constraint | composite_constraint

6
scalar_constraint ::=
     range_constraint | digits_constraint | delta_constraint

7
composite_constraint ::=
     index_constraint | discriminant_constraint

Name Resolution Rules

8
A subtype_mark shall resolve to denote a subtype. The type determined by a subtype_mark is the type of the subtype denoted by the subtype_mark.

8.a
Ramification: Types are never directly named; all subtype_marks denote subtypes - possibly an unconstrained (base) subtype, but never the type. When we use the term anonymous type we really mean a type with no namable subtypes.

Dynamic Semantics

9
The elaboration of a subtype_declaration consists of the elaboration of the subtype_indication. The elaboration of a subtype_indication creates a new subtype. If the subtype_indication does not include a constraint, the new subtype has the same (possibly null) constraint as that denoted by the subtype_mark. The elaboration of a subtype_indication that includes a constraint proceeds as follows:

10 ·
The constraint is first elaborated.

11 ·
A check is then made that the constraint is compatible with the subtype denoted by the subtype_mark.

11.a
Ramification: The checks associated with constraint compatibility are all Range_Checks. Discriminant_Checks and Index_Checks are associated only with checks that a value satisfies a constraint.

12
The condition imposed by a constraint is the condition obtained after elaboration of the constraint. The rules defining compatibility are given for each form of constraint in the appropriate subclause.  These rules are such that if a constraint is compatible with a subtype, then the condition imposed by the constraint cannot contradict any condition already imposed by the subtype on its values. The exception Constraint_Error is raised if any check of compatibility fails.

12.a
To be honest: The condition imposed by a constraint is named after it -a range_constraint imposes a range constraint, etc.

12.b
Ramification: A range_constraint causes freezing of its type. Other constraints do not.

NOTES

13 4
A scalar_constraint may be applied to a subtype of an appropriate scalar type (see 3.5, 3.5.9, and J.3), even if the subtype is already constrained.  On the other hand, a composite_constraint may be applied to a composite subtype (or an access-to-composite subtype) only if the composite subtype is unconstrained (see 3.6.1 and 3.7.1).

Examples

14
Examples of subtype declarations:

15
subtype Rainbow   is Color range Red .. Blue;        --  see 3.2.1
subtype Red_Blue  is Rainbow;
subtype Int       is Integer;
subtype Small_Int is Integer range -10 .. 10;
subtype Up_To_K   is Column range 1 .. K;            --  see 3.2.1
subtype Square    is Matrix(1 .. 10, 1 .. 10);       --  see 3.6
subtype Male      is Person(Sex => M);               --  see 3.10.1

Incompatibilities With Ada 83

15.a
In Ada 9X, all range_constraints cause freezing of their type. Hence, a type-related representation item for a scalar type has to precede any range_constraints whose type is the scalar type.

Wording Changes From Ada 83

15.b
Subtype_marks allow only subtype names now, since types are never directly named. There is no need for RM83-3.3.2(3), which says a subtype_mark can denote both the type and the subtype; in Ada 9X, you denote an unconstrained (base) subtype if you want, but never the type.

15.c
The syntactic category type_mark is now called subtype_mark, since it always denotes a subtype.

3.2.3 Classification of Operations

Static Semantics

1
An operation operates on a type T if it yields a value of type T, if it has an operand whose expected type (see 8.6) is T, or if it has an access parameter (see 6.1) designating T. A predefined operator, or other language-defined operation such as assignment or a membership test, that operates on a type, is called a predefined operation of the type. The primitive operations of a type are the predefined operations of the type, plus any user-defined primitive subprograms.

1.a
Glossary entry: The primitive operations of a type are the operations (such as subprograms) declared together with the type declaration. They are inherited by other types in the same class of types. For a tagged type, the primitive subprograms are dispatching subprograms, providing run-time polymorphism. A dispatching subprogram may be called with statically tagged operands, in which case the subprogram body invoked is determined at compile time. Alternatively, a dispatching subprogram may be called using a dispatching call, in which case the subprogram body invoked is determined at run time.

1.b
To be honest: Protected subprograms are not considered to be "primitive subprograms," even though they are subprograms, and they are inherited by derived types.

1.c
Discussion:  We use the term "primitive subprogram" in most of the rest of the manual. The term "primitive operation" is used mostly in conceptual discussions.

2
The primitive subprograms of a specific type are defined as follows:

3 ·
The predefined operators of the type (see 4.5);

4 ·
For a derived type, the inherited (see 3.4) user-defined subprograms;

5 ·
For an enumeration type, the enumeration literals (which are considered parameterless functions - see 3.5.1);

6 ·
For a specific type declared immediately within a package_specification, any subprograms (in addition to the enumeration literals) that are explicitly declared immediately within the same package_specification and that operate on the type;

7 ·
Any subprograms not covered above [that are explicitly declared immediately within the same declarative region as the type] and that override (see 8.3) other implicitly declared primitive subprograms of the type.

7.a
Discussion:  In Ada 83, only subprograms declared in the visible part were "primitive" (i.e. derivable).  In Ada 9X, mostly because of child library units, we include all operations declared in the private part as well, and all operations that override implicit declarations.

7.b
Ramification: It is possible for a subprogram to be primitive for more than one type, though it is illegal for a subprogram to be primitive for more than one tagged type. See 3.9.

7.c
Discussion:  The order of the implicit declarations when there are both predefined operators and inherited subprograms is described in , "Derived Types and Classes".

8
A primitive subprogram whose designator is an operator_symbol is called a primitive operator.

Incompatibilities With Ada 83

8.a
The attribute S'Base is no longer defined for non-scalar subtypes.  Since this was only permitted as the prefix of another attribute, and there are no interesting non-scalar attributes defined for an unconstrained composite or access subtype, this should not affect any existing programs.

Extensions to Ada 83

8.b
The primitive subprograms (derivable subprograms) include subprograms declared in the private part of a package specification as well, and those that override implicitly declared subprograms, even if declared in a body.

Wording Changes From Ada 83

8.c
We have dropped the confusing term operation of a type in favor of the more useful primitive operation of a type and the phrase operates on a type.

8.d
The description of S'Base has been moved to 3.5, "Scalar Types" because it is now defined only for scalar types.



[Home] [Prev] [Next] [Index]

documentation@rational.com
Copyright © 1993-1998, Rational Software Corporation.   All rights reserved.