3.9.1 Type Extensions
1/2
{
AI95-00345-01}
[
{type extension} {extension
(of a type)} {record
extension} {extension
(of a record type)} {private
extension} {extension
(of a private type)} Every type extension
is a tagged type, and is
either a
record
extension or a
private extension of some other tagged type
,
or a non-interface synchronized tagged type..]
Language Design Principles
1.a
We want to make sure that we can extend a generic
formal tagged type, without knowing its discriminants.
1.b
We don't want to allow components in an extension
aggregate to depend on discriminants inherited from the parent value,
since such dependence requires staticness in aggregates, at least for
variants.
Syntax
2
record_extension_part ::= with record_definition
Legality Rules
3/2
{
AI95-00344-01}
{
AI95-00345-01}
{
AI95-00419-01}
The parent type of a record extension shall not be a class-wide type
nor shall it be a synchronized tagged type (see 3.9.4).
If the parent type
or any progenitor is
nonlimited, then each of the components of the
record_extension_part
shall be nonlimited.
{accessibility
rule (record extension) [partial]} The
accessibility level (see 3.10.2) of a record
extension shall not be statically deeper than that of its parent type.
{generic contract issue [partial]}
In addition to the places where Legality Rules normally
apply (see
12.3), these rules apply also in
the private part of an instance of a generic unit.
3.a
Reason: If the parent is a limited formal
type, then the actual might be nonlimited.
3.b/2
{
AI95-00344-01}
Ada 95 required the record extensions to be the
same level as the parent type. Now we use accessibility checks on class-wide
allocators and return statements to prevent
objects from living longer than their type. A
similar accessibility rule is not needed for private extensions, because
in a package, the rule will apply to the full_type_declaration,
and for a generic formal private extension, the actual is all that matters.
3.c/2
{
AI95-00345-01}
Synchronized tagged types cannot be extended. We
have this limitation so that all of the data of a task or protected type
is defined within the type. Data defined outside of the type wouldn't
be subject to the mutual exclusion properties of a protected type, and
couldn't be used by a task, and thus doesn't seem to be worth the potential
impact on implementations.
4/2
{
AI95-00344-01}
Within the body of a generic unit, or the body
of any of its descendant library units, a tagged type A
type extension shall not be declared
as
a descendant of a formal type declared within the formal part of the
generic unit in a generic body if the parent
type is declared outside that body.
4.a
Reason: This paragraph ensures that a
dispatching call will never attempt to execute an inaccessible subprogram
body.
4.a.1/2
{
AI95-00344-01}
The convoluted wording (“formal type declared
within the formal part”) is necessary to include tagged types that
are formal parameters of formal packages of the generic unit, as well
as formal tagged and tagged formal derived types of the generic unit.
4.b/2
{
AI95-00344-01}
This rule The part
about generic bodies is necessary in order to preserve the contract
model.
4.c/2
{
AI95-00344-01}
If an ancestor Since
a generic unit can be instantiated at a deeper accessibility level than
the generic unit, it is necessary to prevent type extensions whose parent
is declared outside the generic unit. The same is true if the parent
is a formal of the generic unit
, we have a problem.
If the parent is declared in the generic_declaration
(but is not a formal), we don't run afoul of the accessibility rules,
because we know that the instance declaration and body will be at the
same accessibility level. However, we still have a problem in that case,
because it might have an unknown number of abstract subprograms, as in
the following example:
4.d/2
package P is
type T is tagged null record;
function F return T; -- Inherited versions will require overriding be abstract.
end P;
4.e
generic
type TT is tagged private;
package Gp is
type NT is abstract new TT with null record;
procedure Q(X : in NT) is abstract;
end Gp;
4.f/2
package body Gp is
type NT2 is new NT with null record; -- Illegal!
procedure Q(X : in NT2) is begin null; end Q;
-- Is this legal or not? Can't decide because
-- we don't know whether TT had any functions that require go abstract
-- overriding on extension.
end Gp;
4.g
package I is new Gp(TT => P.T);
4.h/2
I.NT is an abstract type with two abstract subprograms:
F (inherited as abstract) and Q (explicitly declared as abstract). But
the generic body doesn't know about F, so we don't know that it needs
to be overridden to make a nonabstract extension of NT. Furthermore, a formal tagged limited private type can be extended with
limited components, but the actual might not be limited, which would
allow assignment of limited types, which is bad. Hence, we have
to disallow this case as well.
4.h.1/2
Similarly, since the actual
type for a formal tagged limited private type can be a nonlimited type,
we would have a problem if a type extension of a limited private formal
type could be declared in a generic body. Such an extension could have
a task component, for example, and an object of that type could be passed
to a dispatching operation of a nonlimited ancestor type. That operation
could try to copy the object with the task component. That would be bad.
So we disallow this as well.
4.i
If TT were declared as abstract, then we could
have the same problem with abstract procedures.
4.j
We considered disallowing all tagged types in
a generic body, for simplicity. We decided not to go that far, in order
to avoid unnecessary restrictions.
4.k
{
accessibility rule (not part of generic
contract) [partial]}
We also considered trying
make the accessibility level part of the contract; i.e. invent some way
of saying (in the
generic_declaration) “all
instances of this generic unit will have the same accessibility level
as the
generic_declaration.” Unfortunately,
that doesn't solve the part of the problem having to do with abstract
types.
4.l/2
This paragraph
was deleted.Children of generic units
obviate the need for extension in the body somewhat.
4.m/2
Ramification: {
AI-00344}
This rule applies to types with ancestors (directly
or indirectly) of formal interface types (see 12.5.5),
formal tagged private types (see 12.5.1),
and formal derived private types whose ancestor type is tagged (see 12.5.1).
Static Semantics
4.1/2
{
AI95-00391-01}
{null extension}
A record extension is a null extension if
its declaration has no known_discriminant_part
and its record_extension_part includes no
component_declarations.
Dynamic Semantics
5
{elaboration (record_extension_part)
[partial]} The elaboration of a
record_extension_part
consists of the elaboration of the
record_definition.
6
69 The term “type extension”
refers to a type as a whole. The term “extension part” refers
to the piece of text that defines the additional components (if any)
the type extension has relative to its specified ancestor type.
6.a
Discussion: We considered other terminology,
such as “extended type.” However, the terms “private
extended type” and “record extended type” did not convey
the proper meaning. Hence, we have chosen to uniformly use the term “extension”
as the type resulting from extending a type, with “private extension”
being one produced by privately extending the type, and “record
extension” being one produced by extending the type with an additional
record-like set of components. Note also that the term “type extension”
refers to the result of extending a type in the language Oberon as well
(though there the term “extended type” is also used, interchangeably,
perhaps because Oberon doesn't have the concept of a “private extension”).
7/2
70 {
AI95-00344-01}
The accessibility rules imply that a tagged type
declared in a library package_specification
can be extended only at library level or as a generic formal. When
an the extension
is declared immediately within a
body package_body,
primitive subprograms are inherited and are overridable, but new primitive
subprograms cannot be added.
8
71 A
name that
denotes a component (including a discriminant) of the parent type is
not allowed within the
record_extension_part.
Similarly, a
name that denotes a component
defined within the
record_extension_part is
not allowed within the
record_extension_part.
It is permissible to use a
name that denotes
a discriminant of the record extension, providing there is a new
known_discriminant_part
in the enclosing type declaration. (The full rule is given in
3.8.)
8.a
Reason: The restriction against depending
on discriminants of the parent is to simplify the definition of extension
aggregates. The restriction against using parent components in other
ways is methodological; it presumably simplifies implementation as well.
9
72 Each visible component of a record extension
has to have a unique name, whether the component is (visibly) inherited
from the parent type or declared in the
record_extension_part
(see
8.3).
Examples
10
Examples of record
extensions (of types defined above in 3.9):
11
type Painted_Point is new Point with
record
Paint : Color := White;
end record;
-- Components X and Y are inherited
12
Origin : constant Painted_Point := (X | Y => 0.0, Paint => Black);
13
type Literal is new Expression with
record -- a leaf in an Expression tree
Value : Real;
end record;
14
type Expr_Ptr
is access all Expression'Class;
--
see 3.10
15
type Binary_Operation is new Expression with
record -- an internal node in an Expression tree
Left, Right : Expr_Ptr;
end record;
16
type Addition is new Binary_Operation with null record;
type Subtraction is new Binary_Operation with null record;
-- No additional components needed for these extensions
17
Tree : Expr_Ptr := -- A tree representation of “5.0 + (13.0–7.0)”
new Addition'(
Left => new Literal'(Value => 5.0),
Right => new Subtraction'(
Left => new Literal'(Value => 13.0),
Right => new Literal'(Value => 7.0)));
Extensions to Ada 83
17.a
{
extensions to Ada 83}
Type
extension is a new concept.
Extensions to Ada 95
17.b/2
{
AI95-00344-01}
{extensions to Ada 95} Type
extensions now can be declared in more nested scopes than their parent
types. Additional accessibility checks on allocators
and return statements prevent objects from outliving their type.
Wording Changes from Ada 95
17.c/2
{
AI95-00345-01}
Added wording to prevent extending synchronized
tagged types.
17.d/2