!standard 13.1.1(18.3/5) 21-11-11 AI22-0002-1/01 !standard 4.3.5(6/5) !standard 4.3.5(10/5) !standard 4.3.5(35/5) !class binding interpretation 21-11-11 !status work item 21-11-11 !status received 21-08-02 !priority Low !difficulty Medium !qualifier Omission !subject Nonoverridable aspects must be primitive !summary Nonoverridable aspects that denote subprograms must denote primitive subprograms. !question Is the following legal? (No.) package Pkg is package Pkg_For_Root is type Root is tagged record X, Y : Integer; end record with Integer_Literal => I_L; package Not_Primitive is function I_L (S : String) return Root is ((0, 0)); end Not_Primitive; use Not_Primitive; end Pkg_For_Root; package Pkg_For_Derived is type Descendant is new Root with record Z : Integer; end record; end Pkg_For_Derived; end Pkg; If it is not legal, which type is illegal? (Root.) !recommendation (See Summary.) !wording Add after 13.1.1(18.3/5): For a nonoverridable aspect of a type T (or part of such an aspect) that denotes one or more subprograms with a parameter or result of T or access T, all of the denoted subprograms shall be primitive for T. AARM Reason: Nonoverridable aspects cannot be changed when inherited. A non-primitive subprogram is not inherited, and thus there would be an inherited reference to a subprogram that does not exist for the derived type. Moreover, the subprogram wouldn't have the correct profile (since it still uses the parent type in the profile, not the derived type). "Part of an aspect" covers the case of aspects that are aggregates (like Aggregate) that contain some parts that denote subprograms. --- Clean-ups: Add after AARM 4.1.6(3.b/3): AARM Reason: For a function that has a parameter of T or access T, a blanket rule in 13.1.1 requires the function to be a primitive operation of T, the wording about the same declaration_list is redundant in that case. That 13.1.1 rule does *not* apply to functions that have parameters of T'Class or access T'Class (which is good, as those can never be primitive); the wording about the declaration_list is necessary in that case. Add after AARM 5.5.1(8.a/3): AARM Reason: For a function that has a parameter of T or access T, a blanket rule in 13.1.1 requires the function to be a primitive operation of T, the wording about the same declaration_list is redundant in that case. That 13.1.1 rule does *not* apply to functions that have parameters of T'Class or access T'Class (which is good, as those can never be primitive); the wording about the declaration_list is necessary in that case. [Question: Do we still need the "declaration_list" rule in this case? For a class-wide routine, it would seem that it could be declared anywhere and it still would work as expected (it doesn't need to be inherited, it just has to exist and any descendant can be used with it). As noted in the notes above, it has no useful effect for specific parameters, as the new blanket rule applies and is more restrictive. Perhaps we could delete that wording from 4.1.6(2-3/5) and 5.5.1(8/5). I'd still retain the notes, without the part about the declaration_list wording. Thoughts??] Modify 4.3.5(6/5): The name specified for Empty for an Aggregate aspect shall denote [a constant of the container type, or denote] exactly one function with a result type of the container type that has no parameters, or that has one in parameter of a signed integer type. Modify AARM 4.3.5(6.a/5): [In the function case, t]{T}he parameter{ of the function}, if present may be used to ... Modify 4.3.5(10/5): If the container type of an Aggregate aspect is a private type, the full type of the container type shall not be an array type.[ If the container type is limited, the name specified for Empty shall denote a function rather than a constant object.] Modify 4.3.5(35/5): * if the aggregate is not an indexed aggregate, [by assignment from the Empty constant, or ]from a call on the Empty function specified in the Aggregate aspect. In the case of an Empty function with a formal parameter, the actual parameter has the following value: !discussion We start by noting that no confirming aspect is possible in this case. 13.1.1(18.4/5) requires that the aspect denote the same delcaration, but that declaration necessarily has the wrong profile (as the result type is wrong). A similar declaration, as in the following: package Pkg2 is package Pkg_For_Root is -- same as in !question type Root is tagged record X, Y : Integer; end record with Integer_Literal => I_L; package Not_Primitive is function I_L (S : String) return Root is ((0, 0)); end Not_Primitive; use Not_Primitive; end Pkg_For_Root; package Pkg_For_Derived is type Descendant is new Root with record Z : Integer; end record with Integer_Literal => I_L; package Not_Primitive is function I_L (S : String) return Descendant is ((0, 0, 0)); end Not_Primitive; use Not_Primitive; end Pkg_For_Derived; end Pkg2; Clearly fails 13.1.1(18.4/5), as it denotes an entirely different declaration which was not inherited. But this means that the type Descendant in the question has an Integer_Literal aspect that returns the wrong type. Originally, the sentence in 13.1.1(18.3/5) "Any legality rule associated with a nonoverridable aspect is re-checked for the derived type, if the derived type is not abstract" was interpreted as making Descendant illegal in this case. However, the profile of an aspect is a Name Resolution Rule, not a Legality Rule, so clearly that rule does not help. Moreover, we do not want to re-resolve the original name, as one can get an altogether different answer (as in the second example). So we need a new, explicit, rule to cover this case. The obvious rule would be to say that a derived type is illegal if it has any inherited nonoverridable aspect (or part thereof) that is not a primitive subprogram (as such subprograms are not inherited). However, a rule like this has to be rechecked in generic units (as it applies even though no aspect is directly specified on the type, and we can only know if the aspect is specified on the actual type). That adds implementation complexity. Moreover, such a rule would provide a back-door way to declare a "final" type (one that can never be derived from). That seems like a bad idea; if there is a need for "final" types, they should be provided explicitly, not as a side-effect of other rules. The alternative is to simply require the subprograms to be primitive in the first place. Such a rule would appear to have some negative side effects. First, such a rule would ban using subprograms imported from other packages. However, this is not a real problem, as all of these operations necessarily have a parameter or result of the type. Those obviously cannot be declared *before* the type in question, and since the names are resolved at the first freezing point, they clearly cannot be declared afterwards (in a child unit), either. So this is not a real concern. Indeed, it has to be intentional that some routine is not primitive (as in the example in the !question); it will only happen for someone trying to make trouble. Second, for a non-derived type declared in a declarative_part (as in a subprogram) has no primitive operations, so such a rule would ban using a nonoverridable aspect on such a type. However, there is a simple mitigation for this problem (declare the type in a package nested in the subprogram's declarative_part). Moreover, these aspects are generally complex aspects used for adding functionality to an abstract data type; such types will almost always be declared in packages and thus there will be no problem in actual use. Therefore, we adopt a rule that most subprograms denoted in nonoverridable aspects must be primitive subprograms. [Aside: If we ever did support "final" types, we could could make the new rule conditional on the type not being final.] ----- The new rule has a side-effect that several existing aspects have restricts with a similar effect to the new blanket rule. We remove all of those existing rules (it's not good to have two rules with similar but not exactly the same effect). We also remove the option to use a constant as the initial value for the Aggregate aspect. A constant acts very much like a non-primitive function for the type, and we just decided we don't want those. Note that one can easily write an expression function that returns a constant if one really wants to use a constant for initialization (some of the Ada.Containers do that already) - no body is required. ----- Note that the proposed rule is mildly incompatible. If someone has used one of the Ada 2012 nonoverridable aspects (Implicit_Dereference, Constant_Indexing, Variable_Indexing, Default_Iterator) to which this rule applies with a non-primitive subprogram (including the case where the type is declared in a declarative_part of a subprogram or other entity), and did not derive from them, the aspect would have worked as expected but now would be illegal. As described previously, it is thought that such cases will be unlikely. Also note that this rule does not apply to Default_Iterator/Constant_Indexing/Variable_Indexing if the subprogram that is resolved has a parameter of T'Class or access to T'Class (the parameter or result type is not T in that case). It also does not apply to Iterator_Element (which names a type), Implicit_Dereference (which names a discriminant), No_Controlled_Parts (which is a Boolean value), or Max_Entry_Queue_Length (which is an integer value). !corrigendum 4.3.5(6/5) @drepl The @fa specified for Empty for an Aggregate aspect shall denote a constant of the container type, or denote exactly one function with a result type of the container type that has no parameters, or that has one @b parameter of a signed integer type. @dby The @fa specified for Empty for an Aggregate aspect shall denote exactly one function with a result type of the container type that has no parameters, or that has one @b parameter of a signed integer type. !corrigendum 4.3.5(10/5) @drepl If the container type of an Aggregate aspect is a private type, the full type of the container type shall not be an array type. If the container type is limited, the name specified for Empty shall denote a function rather than a constant object. @dby If the container type of an Aggregate aspect is a private type, the full type of the container type shall not be an array type. !corrigendum 4.3.5(35/5) @drepl @xbullet is not an indexed aggregate, by assignment from the Empty constant, or from a call on the Empty function specified in the Aggregate aspect. In the case of an Empty function with a formal parameter, the actual parameter has the following value:> @dby @xbullet is not an indexed aggregate, from a call on the Empty function specified in the Aggregate aspect. In the case of an Empty function with a formal parameter, the actual parameter has the following value:> !corrigendum 13.1.1(18.3/5) @dinsa Certain type-related aspects are defined to be @i; 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 @i; such aspects are not inherited, but they can @i 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 @i; 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. @dinst For a nonoverridable aspect of a type @i (or part of such an aspect) that denotes one or more subprograms with a parameter or result of T or @b T, all of the denoted subprograms shall be primitive for @i. !ACATS test !appendix ****************************************************************