3.9 Tagged Types and Type Extensions
types and type extensions support object-oriented programming, based
on inheritance with extension and run-time polymorphism via dispatching
A record type or private type
that has the reserved word tagged
in its declaration is called
type. In addition, an interface type is a tagged type,
as is a task or protected type derived from an interface (see 3.9.4
When deriving from a tagged type, as for any derived type, additional
primitive subprograms may be defined, and inherited primitive subprograms
may be overridden.
type is called an extension
of its ancestor types, or simply a
type extension is also a tagged type, and is a record extension
or a private extension
of some other tagged type, or a noninterface
synchronized tagged type (see 3.9.4
). A record
extension is defined by a derived_type_definition
with a record_extension_part
), which may include the definition
of additional components. A private extension, which is a partial view
of a record extension or of a synchronized tagged type, can be declared
in the visible part of a package (see 7.3
or in a generic formal part (see 12.5.1
An object of a tagged type has
an associated (run-time) tag
that identifies the specific tagged
type used to create the object originally. The tag of an operand of a
class-wide tagged type T
'Class controls which subprogram body
is to be executed when a primitive subprogram of type T
to the operand (see 3.9.2
a tag to control which body to execute is called dispatching
The tag of a specific tagged type identifies the
of the type, and for a type extension, is sufficient to uniquely identify
the type among all descendants of the same ancestor. If a declaration
for a tagged type occurs within a generic_package_declaration
then the corresponding type declarations in distinct instances of the
generic package are associated with distinct tags. For a tagged type
that is local to a generic package body and with all of its ancestors
(if any) also local to the generic body, the language does not specify
whether repeated instantiations of the generic body result in distinct
The following language-defined
library package exists:
Tag is private
Expanded_Name(T : Tag) return
Wide_Expanded_Name(T : Tag) return
Wide_Wide_Expanded_Name(T : Tag) return
External_Tag(T : Tag) return
Internal_Tag(External : String) return
Descendant_Tag(External : String; Ancestor : Tag) return
Is_Descendant_At_Same_Level(Descendant, Ancestor : Tag)
Parent_Tag (T : Tag) return
Tag_Array is array
Interface_Ancestor_Tags (T : Tag) return
Is_Abstract (T : Tag) return
... -- not specified by the language
No_Tag is the default initial value of type Tag.
The function Wide_Wide_Expanded_Name returns the
full expanded name of the first subtype of the specific type identified
by the tag, in upper case, starting with a root library unit. The result
is implementation defined if the type is declared within an unnamed block_statement
The function Expanded_Name (respectively, Wide_Expanded_Name)
returns the same sequence of graphic characters as that defined for Wide_Wide_Expanded_Name,
if all the graphic characters are defined in Character (respectively,
Wide_Character); otherwise, the sequence of characters is implementation
defined, but no shorter than that returned by Wide_Wide_Expanded_Name
for the same value of the argument.
The function External_Tag returns a string to be
used in an external representation for the given tag. The call External_Tag(S'Tag)
is equivalent to the attribute_reference
S'External_Tag (see 13.3
The string returned by the functions Expanded_Name,
Wide_Expanded_Name, Wide_Wide_Expanded_Name, and External_Tag has lower
The function Internal_Tag returns a tag that corresponds
to the given external tag, or raises Tag_Error if the given string is
not the external tag for any specific type of the partition. Tag_Error
is also raised if the specific type identified is a library-level type
whose tag has not yet been created (see 13.14
The function Descendant_Tag returns the (internal)
tag for the type that corresponds to the given external tag and is both
a descendant of the type identified by the Ancestor tag and has the same
accessibility level as the identified ancestor. Tag_Error is raised if
External is not the external tag for such a type. Tag_Error is also raised
if the specific type identified is a library-level type whose tag has
not yet been created, or if the given external tag identifies more than
one type that has the appropriate Ancestor and accessibility level.
The function Is_Descendant_At_Same_Level returns
True if the Descendant tag identifies a type that is both a descendant
of the type identified by Ancestor and at the same accessibility level.
If not, it returns False.
For the purposes of the dynamic semantics of functions
Descendant_Tag and Is_Descendant_At_Same_Level, a tagged type T2 is a
of a type T1 if it is the same as T1, or if its parent
type or one of its progenitor types is a descendant of type T1 by this
rule, even if at the point of the declaration of T2, one of the derivations
in the chain is not visible.
The function Parent_Tag returns the tag of the
parent type of the type whose tag is T. If the type does not have a parent
type (that is, it was not defined by a derived_type_definition
then No_Tag is returned.
The function Interface_Ancestor_Tags returns an
array containing the tag of each interface ancestor type of the type
whose tag is T, other than T itself. The lower bound of the returned
array is 1, and the order of the returned tags is unspecified. Each tag
appears in the result exactly once. If the type whose tag is T has no
interface ancestors, a null array is returned.
The function Is_Abstract returns True if the type
whose tag is T is abstract, and False otherwise.
For every subtype S of a tagged type T (specific
or class-wide), the following attributes are defined:
S'Class denotes a subtype of
the class-wide type (called T
'Class in this International Standard)
for the class rooted at T
(or if S already denotes a class-wide
subtype, then S'Class is the same as S).
is unconstrained. However, if S is constrained, then the values of S'Class
are only those that when converted to the type T
belong to S.
S'Tag denotes the tag of the
(or if T
is class-wide, the tag of the root type
of the corresponding class). The value of this attribute is of type Tag.
Given a prefix
X that is of a class-wide tagged type (after any implicit dereference),
the following attribute is defined:
X'Tag denotes the tag of X. The
value of this attribute is of type Tag.
The following language-defined
generic function exists:
T (<>) is abstract tagged limited private
Parameters (<>) is limited private
Constructor (Params : not null access
T is abstract
(The_Tag : Tag;
Params : not null access
Convention => Intrinsic;
a mechanism to create an object of an appropriate type from just a tag
value. The function Constructor is expected to create the object given
a reference to an object of type Parameters.
The tag associated
with an object of a tagged type is determined as follows:
The tag of a stand-alone object,
a component, or an aggregate
of a specific tagged type T
The tag of an object created
by an allocator for an access type with a specific designated tagged
, identifies T
The tag of an object of a class-wide
tagged type is that of its initialization expression.
The tag of the result returned
by a function whose result type is a specific tagged type T
The tag of the result returned
by a function with a class-wide result type is that of the return object.
The tag is preserved by type
conversion and by parameter passing. The tag of a value is the tag of
the associated object (see 6.2
Tag_Error is raised by a call of Descendant_Tag,
Expanded_Name, External_Tag, Interface_Ancestor_Tags, Is_Abstract, Is_Descendant_At_Same_Level,
Parent_Tag, Wide_Expanded_Name, or Wide_Wide_Expanded_Name if any tag
passed is No_Tag.
An instance of Tags.Generic_Dispatching_Constructor
raises Tag_Error if The_Tag does not represent a concrete descendant
of T or if the innermost master (see 7.6.1
of this descendant is not also a master of the instance. Otherwise, it
dispatches to the primitive function denoted by the formal Constructor
for the type identified by The_Tag, passing Params, and returns the result.
Any exception raised by the function is propagated.
If an internal tag provided
to an instance of Tags.Generic_Dispatching_Constructor or to any subprogram
declared in package Tags identifies either a type that is not library-level
and whose tag has not been created (see 13.14
or a type that does not exist in the partition at the time of the call,
then execution is erroneous.
The implementation of Internal_Tag and Descendant_Tag
may raise Tag_Error if no specific type corresponding to the string External
passed as a parameter exists in the partition at the time the function
is called, or if there is no such type whose innermost master is a master
of the point of the function call.
Internal_Tag should return the tag of a type,
if one exists, whose innermost master is a master of the point of the
70 A type declared with the reserved word
should normally be declared in a package_specification
so that new primitive subprograms can be declared for it.
71 Once an object has been created, its
tag never changes.
72 Class-wide types are defined to have
unknown discriminants (see 3.7
). This means
that objects of a class-wide type have to be explicitly initialized (whether
created by an object_declaration
or an allocator
and that aggregate
have to be explicitly qualified with a specific type when their expected
type is class-wide.
73 The capability provided by Tags.Generic_Dispatching_Constructor
is sometimes known as a factory
Examples of tagged
type Point is tagged
X, Y : Real := 0.0;
type Expression is tagged null record;
-- Components will be added by each extension
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe