Version 1.1 of ai12s/ai12-0419-1.txt

Unformatted version of ai12s/ai12-0419-1.txt version 1.1
Other versions for file ai12s/ai12-0419-1.txt

!standard 3.2.4(1/5)          21-01-14 AI12-0419-1/01
!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 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.
We have two options in this AI relating to the user-defined literal aspects. In OPTION 1, the user-defined literal aspects are nonoverridable. In OPTION 2, these aspects don't quite fit into any of the above categories, but the closest is implicitly composed.
!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? (OPTION 1: it is nonoverridable; OPTION 2: it is similar to "implicitly constructed" but requires re-specifying the aspect for a non-null type extension.)
!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): [OPTION 1]
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 3.9.2(1/5): [OPTION 2]
The primitive subprograms of a tagged type, the subprograms declared by formal_abstract_subprogram_declarations, the subprograms identified by the user-defined literal aspects of a specific tagged type (see 4.2.1){, the Put_Image attribute of a specific tagged type}, 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): [OPTION 1]
User-defined literal aspects are [inherited according to the rules given in 13.1] nonoverridable (see 13.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. {[Redudant: 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 suggest two options for handling user-defined literal aspects:
a) OPTION 1: Treat them as nonoverridable, meaning that in a derived type the parent aspect is inherited, and the named subprogram can be overridden to change the details of the conversion from string(s).
b) OPTION 2: Treat them as a separate operation, where they are inherited as is, and need to be re-specified to do anything different, even if it is to just use the overridding of the previously named primitive. 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.
The AI author recommends OPTION 1, but has retained OPTION 2 as it matches the current semantics.
!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;
In OPTION 1, the overriding From_String is used for converting integer literals for T2, but in OPTION 2, the overriding From_String is not used, unless you repeat the "with Integer_Literal => From_String" on the declaration of T2. In OPTION 2, you had the ability to have T2 use a different operation for converting literals. In OPTION 1, you are limited to using "From_String" in all descendants, because the aspect is nonoverridable.
!ASIS
[Not sure. It seems like some new capabilities might be needed, but I didn't check - Editor.]
!ACATS test
ACATS B- and C-Tests are needed to check that Put_Image works properly for derived types. If Option 1 is chosen, then we also need ACATS B- and C-Tests are needed to check that the user-defined literal aspects are nonoverrideable. For option 2, we also need ACATS B- and C-Tests are needed to check that the original user-defined literal aspects is used for a derived type.
No tests are needed for other aspects as no semantic change is needed.
!appendix

****************************************************************

   


Questions? Ask the ACAA Technical Agent