Version 1.2 of ai12s/ai12-0419-1.txt
!standard 3.2.4(1/5) 21-01-21 AI12-0419-1/02
!standard 3.2.4(29.5/4)
!standard 3.9.2(1/5)
!standard 4.2.1(6/5)
!standard 4.10(4/5)
!standard 4.10(7/5)
!standard 4.10(19/5)
!standard 7.3.2(3/4)
!standard 7.3.3(2/5)
!standard 12.5.1(21/3)
!standard 13.1(15.9/5)
!standard 13.1.1(18.3/5)
!standard 13.13.2(8.1/3)
!standard 13.13.2(25/3)
!standard 13.13.2(25.1/2)
!standard 13.13.2(25.1/2)
!standard 13.13.2(42/2)
!class Amendment 21-01-14
!status Amendment 1-2012 21-01-21
!status ARG Approved 16-0-0 21-01-20
!status work item 21-01-14
!status received 21-01-14
!priority Low
!difficulty Medium
!subject Aspect inheritance and reemergence
!summary
Type-related and subtype-specific aspects that can mention subprograms
by name fall into different categories relating to whether and how they
are inherited, and whether for a formal untagged type, the operations of
the ancestor reemerge in an instance, or the aspects of the actual are
always used:
1) implicitly composed
Implicitly composed aspects are not inherited per se, but the
aspect for a derived type is implicitly composed from that of its
parent type. The aspects of an ancestor never "reemerge" in a
generic; the actual type's "actual" aspect definition is invoked.
This makes sense because these aspects are generally defined for
private types, and in that case there is no ancestor aspect to
reemerge.
2) additive
Additive aspects are not inherited, but they "apply" to their
descendants, using a "notional formal derived type" model. In
a generic, the type's "actual" aspect definition is invoked
as appropriate, even if untagged. As with the implicitly
composed aspects, these are meaningful on private types,
so reemergence of an ancestor's aspect would not make sense.
3) nonoverridable
Nonoverridable aspects are inherited, but cannot be overridden
except with a "confirming" definition which matches that of the
parent type as defined in 13.1. On the other hand, the named
subprograms can be overridden, and that is the way to alter the
effect of a nonoverridable aspect in a derived type. For a formal
untagged derived type, the ancestor's nonoverridable aspects, if
any, reemerge, which is not surprising because the primitive
subprograms of the untagged ancestor reemerge as well.
Ancestor aspects of formal tagged types never reemerge thanks to the
rule that the actual type's run-time tag controls which body is
executed.
For uniformity, we change the description of stream attributes of
untagged types to use the "implicitly composed" terminology rather than
inheritance, to better match what happens with tagged stream attributes.
This is not intended to change the semantics in any way; it is just a
presentation change that hopefully clarifies the semantics.
The Put_Image aspect is considered to be implicitly composed as well.
The user-defined literal aspects are nonoverridable.
!question
Is the Put_Image aspect inherited by a derived type? (Not exactly; it is
defined by default by a call on the parent's Put_Image, composed with,
if tagged, the Put_Image of any extension components.)
If not, what happens with untagged derived types? (They use an
implicitly defined Put_Image that calls the parent Put_Image.)
Does the Put_Image of the ancestor of a formal derived type reemerge in
a generic instance, or is the actual type's Put_Image used? (Actual
type.)
What are the general rules for inheritance and reemergence of
operational aspects? (This AI attempts to clarify them.)
What are the inheritance and re-emergence rules for the user-defined
literal aspects? (They are nonoverridable.)
!recommendation
See !summary.
!wording
[relative to AARM 202X Draft 27]
Modify 3.2.4(1/5):
The language-defined predicate aspects Static_Predicate and
Dynamic_Predicate may be used to define properties of subtypes. A
predicate specification is an aspect_specification for one of the two
predicate aspects. General rules for aspects and aspect_specifications
are found in Clause 13 (13.1 and 13.1.1 respectively). The predicate
aspects are assertion aspects (see 11.4.2).{ [Redundant: The
predicate aspects are not inherited, but their effects are additive,
as defined below.]}
Modify 3.2.4(29.5/4):
* if S is a first subtype, the value is tested to determine whether it
satisfies the predicates of the parent and progenitor subtypes (if
any) of S (in an arbitrary order){, after a (view) conversion of the
value to the corresponding parent or progenitor type};
Modify 3.9.2(1/5):
The primitive subprograms of a tagged type, the subprograms declared
by formal_abstract_subprogram_declarations, the [subprograms
identified by the user-defined literal aspects]{Put_Image attribute}
of a specific tagged type (see [4.2.1]{4.10}), and the stream
attributes of a specific tagged type that are available (see 13.13.2)
at the end of the declaration list where the type is declared are
called dispatching operations. [... rest as before]
Modify 4.2.1(6/5):
User-defined literal aspects are [inherited according to the rules
given in 13.1] nonoverridable (see 13.1.1).
Modify 4.10(4/5):
The Put_Image attribute may be specified for any specific type T
either via an attribute_definition_clause or via an
aspect_specification specifying the Put_Image aspect of the type.{
[Redundant: The Put_Image aspect is not inherited, but rather is
implicitly composed for derived types, as defined below.]}
Add after 4.10(7/5):
For an untagged derived type, the default implementation of
T'Put_Image invokes the Put_Image for its parent type on
a conversion of the parameter of type T to the parent type.
Move a slight modification of 4.10(17/5, 17.a/5) here (immediately before (8/5)):
For a type extension, the default implementation of T'Put_Image
depends on whether there exists a noninterface ancestor of T (other
than T itself) for which the Put_Image aspect has been [Redundant:
[explicitly]{directly}] specified. If so, then T'Put_Image will
generate an image based on extension aggregate syntax where the
ancestor type of the extension aggregate is the nearest ancestor type
whose Put_Image aspect has been specified.
Discussion: This might generate an image such as "(This Text Was
User-Generated with C1 => 123, C2 => 456)" where the "This Text was
User-Generated" portion of the text was generated by the call to the
user-specified Put_Image routine {for the ancestor}.
Move a modification of 4.10(18/5) here (immediately before 4.10(8/5)):
{For a type extension where}[If] no such ancestor exists{, or for any
nonderived type}, [then] the default implementation of T'Put_Image is
[the same as described below for an untagged record type.] {defined as
follows:}
Modify 4.10(19/5):
For [an untagged]{a} record type[, a specific tagged record type other
than a type extension which meets the criteria described in the
previous paragraph,] or a protected type, the default implementation
of T'Put_Image generates an image based on (named, not positional)
record aggregate syntax (except that for a protected type, the initial
left parenthesis is followed by "PROTECTED with "). Component names
are displayed in upper case, following the rules for the image of an
enumeration value. Component values are displayed via calls to the
component type's Put_Image procedure.
Modify 7.3.2(3/4):
Type_Invariant'Class
This aspect shall be specified by an expression, called an invariant
expression. Type_Invariant'Class may be specified on a
private_type_declaration, or a private_extension_declaration, or a
full_type_declaration for an interface type. Type_Invariant'Class
determines a class-wide type invariant for a tagged type. {[Redundant:
The Type_Invariant'Class aspect is not inherited, but its effects are
additive, as defined below.]}
Modify 7.3.3(2/5):
Default_Initial_Condition
This aspect shall be specified by an expression, called a default
initial condition expression. Default_Initial_Condition may be
specified on a private_type_declaration, a
private_extension_declaration, a formal_private_type_definition, or a
formal_derived_type_definition. {[Redundant: The
Default_Initial_Condition aspect is not inherited, but its effects are
additive, as defined below.]}
Add after 12.5.1(21/3):
In an instance, the implicitly composed and additive aspects (see
13.1.1) of a formal type are those of the actual; for a nonoverridable
aspect, a formal derived type inherits the aspect if the ancestor or
any progenitor has the aspect, according to the rules given in 13.1.
Delete 13.1(15.9/5) [NOTE: it is no longer relevant because
implicitly-composed aspects are not inherited, even for untagged
derived types. Here is what it currently says:
When an aspect that is a subprogram is inherited, the derived type
inherits the aspect in the same way that a derived type inherits a
user-defined primitive subprogram from its parent (see 3.4).]
Modify 13.1.1(18.3/5):
Certain type-related aspects are defined to be /nonoverridable/{; all
such aspects are inherited by derived types according to the rules
given in 13.1. Any legality rule associated with a nonoverridable
aspect is re-checked for the derived type, if the derived type is not
abstract. Certain type-related and subtype-specific aspects are
defined to be /additive/; such aspects are not inherited, but they can
/apply/ to the types derived from, or the subtypes based on, the
original type or subtype, as defined for each such aspect. Finally,
certain type-related aspects are /implicitly composed/; such aspects
are not inherited, but rather a default implementation for a derived
type is provided, as defined for each such aspect, based on that of
its parent type, presuming the aspect for the parent type is available
where the derived type is declared, plus those of any new components
added as part of a type extension.}
Modify 13.13.2(8.1/3):
For an untagged derived type, {the default implementation of} the
Write (resp. Read) attribute {invokes the corresponding attribute
of the parent type,} [inherited according to the rules given in 13.1]
if the attribute is [[Redundant: specified and]] available for the
parent type at the point where T is declared. [For a tagged derived
type, these attributes are not inherited, but rather the default
implementations are used.] {
For type extensions, in the default implementation, the Write or
Read attribute for the parent type is called, followed by the Write or
Read attribute of each component of the extension part, in canonical
order. For a limited type extension, if the attribute of the parent
type or any progenitor type of T is available anywhere within the
immediate scope of T, and the attribute of the parent type or the type
of any of the extension components is not available at the freezing
point of T, then the attribute of T shall be directly specified.}
Modify 13.13.2(8/2):
The default implementations of the Write and Read attributes {for
nonderived types}, where available, execute as follows:
Modify 13.13.2(9/3): [NOTE: Deleting text that was moved to precede
(8/2) above]
For elementary types, Read reads (and Write writes) the number of
stream elements implied by the Stream_Size for the type T; the
representation of those stream elements is implementation defined. For
composite types, the Write or Read attribute for each component
(excluding those, if any, that are not components of the nominal type
of the object) is called in canonical order, which is last dimension
varying fastest for an array (unless the convention of the array is
Fortran, in which case it is first dimension varying fastest), and
positional aggregate order for a record. Bounds are not included in
the stream if T is an array type. If T is a discriminated type,
discriminants are included only if they have defaults. If T is a
tagged type, the tag is not included. [For type extensions, the Write
or Read attribute for the parent type is called, followed by the Write
or Read attribute of each component of the extension part, in
canonical order. For a limited type extension, if the attribute of the
parent type or any progenitor type of T is available anywhere within
the immediate scope of T, and the attribute of the parent type or the
type of any of the extension components is not available at the
freezing point of T, then the attribute of T shall be directly
specified.]
Modify 13.13.2(25/3):
For an untagged derived type, {the default implementation of} the
Output (resp. Input) attribute {invokes the corresponding attribute of
the parent type,} [inherited according to the rules given in 13.1] if
the attribute is [[Redundant: specified and]] available for the parent
type at the point where T is declared. [For a tagged derived type,
these attributes are not inherited, but rather the default
implementations are used.] {For any other type, the default
implementations of the Output and Input attributes, where available,
execute as follows:}
Delete 13.13.2(25.1/2): [NOTE: Its content has been moved into 25/3 above.]
Modify 13.13.2(42/2):
T is a limited untagged derived type, and the attribute [was inherited]
{is available} for the {parent} type.
!discussion
Almost all of the above wording is intended to clarify the existing
inheritance and reemergence rules, rather than establish new rules.
However, there are two significant changes:
1) We have said that the Put_Image aspects are not inherited, but are
rather implicitly composed. Before we were silent on what happened
with an untagged derived type.
2) We treat user-defined literal aspects as nonoverridable. The current
wording suggests that they are a separate operation, but says that
they are inherited as defined in 13.1. This presumably was referring to
stream-attribute style inheritance, although nonoverridable inheritance
is also (partially) defined there.
We considered using a form of "implicitly composed" inheritance for
user-defined literals. This would have the advantage that an extension could
have the literal operation and the originally associated operation do
different things (which could be necessary if the named operation is useful
user operation in its own right, such as the From_String conversion originally
defined for BigNums). But it would have the disadvantage that for a non-null
type extension, the aspect is required to be re-specified, again, even if
it is to just use the overriding of the previously named primitive. That would
necessary as such functions are required to be overridden, and a similar rule
would be needed for such aspects.
!examples
type T is private
with Integer_Literal => From_String;
function From_String(S : String) return T;
...
type T2 is new T;
overriding
function From_String(S : String) return T2;
The overriding From_String is used for converting integer literals for T2.
In the rejected alternative, the overriding From_String would not be
used, unless you repeat the "with Integer_Literal => From_String" on the
declaration of T2. In this alternative, you would have had the ability to have
T2 use a different operation for converting literals. As defined, you are
limited to using "From_String" in all descendants, because the aspect is
nonoverridable.
!ASIS
No ASIS effect.
!ACATS test
ACATS B- and C-Tests are needed to check that Put_Image works properly
for derived types. We also need ACATS B- and C-Tests are needed to
check that the user-defined literal aspects are nonoverrideable.
No tests are needed for other aspects as no semantic change is intended.
!appendix
****************************************************************
Questions? Ask the ACAA Technical Agent