AI22-0154-1
!standard 4.1.6(2/7) 26-03-11 AI22-0154-1/05
!standard 4.1.6(3/7)
!standard 8.6(26)
!standard 13.1.1(8/6)
!class Binding Interpretation 26-02-09
!status Revision-202Y 26-02-20
!status ARG Approved 9-0-1 26-05-12
!status work item 26-03-05
!status ARG Approved 7-1-1 26-02-17
!status work item 26-02-09
!status received 26-02-09
!assigned author Gary Dismukes
!submitter Gary Dismukes
!priority Medium
!difficulty Medium
!qualifier Clarification
!subject Revised resolution of indexing aspects
The resolution rules for the subprogram names given in the indexing aspects are revised to include the aspects' type requirements for formal parameters and results. The rules for expected profiles are extended to clarify that aspects that name subprograms can potentially resolve to denote multiple subprograms.
The current rules for indexing aspects (as clarified by AI22-0146-1) have the effect of making cases like the following illegal:
package Vectors is
type Int_Vector is private
with
Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference;
... definitions of reference types and indexing functions ...
type Float_Vector is private
with
Constant_Indexing => Constant_Reference,
Variable_Indexing => Reference;
... definitions of reference types and indexing functions ...
end Vectors;
The presence of same-named indexing functions for multiple types declared immediately within the same package is illegal, because the resolution of the subprogram names in the aspects must consider all the functions with the same name as given in the aspect declared in the same package.
A similar situation can occur with inherited indexing functions, as in this example:
with Ada.Containers.Doubly_Linked_Lists;
use Ada.Containers;
package Indexable_Types is
type Rec1 is record ...;
package Lists_Of_Rec1 is new Doubly_Linked_Lists (Rec1);
type List_Of_Rec1 is new Lists_Of_Rec1.List with
private;
function Reference
(Container : aliased in out List_Of_Rec1;
Position : Cursor) return
Lists_Of_Rec1.Reference_Type;
type Rec2 is record ...;
package Lists_Of_Rec2 is new Doubly_Linked_Lists (Rec2);
type List_Of_Rec2 is new Lists_Of_Rec2.List with
private;
-- inherits reference functions and might override them
end Indexable_Types;
The type List_Of_Rec1 inherits indexing aspects from type List in the instantiation Lists_Of_Rec1 and overrides the function Reference, and type List_Of_Rec2 inherits from type List in a different instantiation, and might (or might not) also override it. The inherited aspects are then resolved at the end of the enclosing library package (technically at the end of its visible part). In the case of each of those types, there are two possible interpretations for the name in the Variable_Indexing aspect, one coming from the first type and one coming from the second type. And because the interpretation coming from the other type does not satisfy the requirements of the profile for that aspect, it's illegal. (That's true whether or not the inherited functions are overridden.)
It seems undesirable that examples like the above are illegal, given that it's clear that the same-named functions are indexing functions that have first formals associated with independent types.
Revise the rules recently added (by AI22-0146-1) about the expected profile of the indexing aspects being "any function" to include the profile requirements of the existing legality rules for the first parameter. That has the effect of excluding other functions of the same name from consideration by the resolution of the subprogram name specified by those aspects.
As a result, only functions whose first parameter is the type to which the aspects apply can be considered as candidate interpretations, and same-named functions for other types (that might also define indexing operations for those types) will not make the aspects illegal.
Also, revise the rules related to expected profiles to clarify that aspects can potentially denote multiple subprograms (as in the case of the indexing aspects) that satisfy an expected profile according to more open-ended rules, rather than strictly requiring type conformance.
Modify 4.1.6(2/7):
This aspect shall be specified by a name that denotes one or more functions[ declared immediately within the same declaration list in which T, or the declaration completed by T, is declared]. {When directly specified, the}[The] expected profile of this aspect is {satisfied by every}[any] function[. All such functions shall have]{ that has} at least two parameters, the first of which is of type T or{, if T is a tagged type,} T'Class, or is an {access}[access-to-constant] parameter {designating one of these types}[with designated type T or T'Class].{ If the first parameter of such a function is an access parameter, it shall be an access-to-constant parameter.}
Modify 4.1.6(3/7):
This aspect shall be specified by a name that denotes one or more functions[ declared immediately within the same declaration list in which T, or the declaration completed by T, is declared]. {When directly specified, the}[The] expected profile of this aspect is {satisfied by every}[any] function[. All such functions shall have]{ that has} at least two parameters, the first of which is of type T or{, if T is a tagged type,} T'Class, or is an access parameter {designating one of these types}[with designated type T or T'Class]. All such functions shall have an explicitly aliased variable result, or a return type that is a reference type (see 4.1.5), whose reference discriminant is of an access-to-variable type.
Replace AARM 4.1.6(3.c/6) [which no longer applies] by:
Ramification:When the aspect is not directly specified, it is inherited by the rules given in 13.1, and thus the expected profile is not used or needed. We include "When directly specified" to make that clear.
A derived type can inherit a class-wide operation as an indexing function, but the user cannot confirm such an indexing function, because the explicit specification would violate the expected profile requirements for direct aspect specifications. This is unfortunate, but since one cannot change an inherited class-wide indexing function, it seems better to not allow a confirming aspect specification than to create a substantially more complex rule for the expected profile.
Modify 8.6(26):
In certain contexts, [redundant: such as in a subprogram_renaming_declaration,] the Name Resolution Rules define an expected profile for a given name; in such cases, the name shall resolve to the name of a callable entity whose profile is type conformant with the expected profile{, or, where explicitly allowed, to one or more callable entities whose profiles satisfy the expected profile with respect to the required number and types of parameters, and, for a function, the type of the result}.
Modify 13.1.1(8/6):
With the current rules, the presence of any unrelated functions in the same list of declarations with the same name as an indexing function of another type will cause ambiguities for the resolution of an indexing aspect of that other type. That can be viewed as a feature, in that it can catch cases where intended indexing functions are written with the wrong type for their first formal (though that's really only a benefit when more than one such function is provided for a given aspect), but can also lead to creating unexpected ambiguities in cases where a programmer wants to declare multiple types in the same package using the same naming scheme for the types' indexing aspects.
This can be particularly surprising in derived type cases, where there might not even be any explicit declarations for the conflicting functions. There are workarounds (like creating additional packages), but it's unpleasant to require restructuring in such cases.
It seems reasonable to make the resolution rules for these aspects more specific, so rather than saying that the name must resolve to be "any function", we include the first parameter's type as part of the resolution rule. Compilers can still flag other functions with the same name with a warning if they want to, in order to retain the maintenance benefit of catching miswritten functions.
Note that AI22-0075-1 changes the return type of Variable_Indexing to allow “an explicitly aliased variable result” as well as the existing reference type. Since constancy and aliasedness are, like modes, not traditionally considered as part of resolution, this boils down to essentially allowing the return type to be any type (along with a legality check). Thus we include nothing about the return type in the expected profile and retain the existing final sentence, which is (still) intended to be treated as a Legality Rule.
We also exclude the “access-to-constant” part of Constant_Indexing from resolution for similar reasons. This required introducing a small trailing sentence, which is intended to be interpreted as a Legality Rule.
Along with the rule changes specific to the indexing aspects, it also seems desirable to adjust the rules in 8.6 and 13.1.1 related to expected profiles to make it clearer that subprogram-valued aspects can resolve to designate more than one subprogram. An AARM paragraph was already added by AI22-0146-1 to indicate that possibility for resolving such aspects, but the rules should reflect that.
We also fix a problem introduced by AI22-0136-1, where we talk about T’Class even though T might be an untagged type. We redo the wording to clarify that T’Class is only relevant when T is a tagged type. The form of that wording was borrowed from the wording of 4.1.3(9.2/7), making it more consistent and a bit less redundant.
Another detected problem involves derived types that inherit aspects defined with class-wide operations of the ancestor type. Such operations probably are not in the declaration list for the derived type, and thus the Legality Rule recheck mandated for nonoverridable aspects usually will fail.
We determined that the part of the rule requiring the same declaration list is no longer needed. For functions with a specific type first parameter, a nonoverridable aspect requires that they are primitive operations of the type. Those necessarily are in the correct declaration list. For functions with a class-wide first parameter, the requirement that it have T’Class requires that it be declared in the same unit as T (the aspect specification being given on the type declaration of T means that functions from other imported units can never have the correct profile, and of course the aspect can only refer to subprograms that it can see, so routines declared later cannot be considered). As such, the only effect of the existing rule is to prevent a class-wide function declared in a nested package from being considered, which is unlikely and unimportant.
Note that an inherited aspect that specifies a class-wide function cannot be confirmed, as the named subprogram will have the wrong type for the parameter type. Specifically:
package RPack is
type Root is tagged ...
with Constant_Indexing => My_Index;
function My_Index (A : in Root’Class; I : in Integer)
return Integer; -- (A)
type Child is new Root with Constant_Indexing => My_Index;
function My_Index (A : in Child’Class; I : in Integer)
return Integer; -- (1)
function My_Index (A : in Child; F : in Float)
return Integer; -- (2)
end RPack;
The Constant_Indexing on Child is illegal regardless of whether either or both of the functions (1) and (2) are present. If both are present, the aspect is illegal by 13.1.1(18.2/5), which makes it illegal to have an aspect designate both class-wide and primitive subprograms.
If only (2) is present, then the aspect is illegal by 13.1.1(18.5/5) which requires the aspect to be confirming, meaning that all of the declarations that would have been inherited need to be included (and (A) is not included in the directly specified aspect). Similarly, if only (1) is present, then again 13.1.1(18.5/5) is violated. Finally, if neither (1) nor (2) is included, the specification is illegal as there is no matching function with a first parameter of Child or Child’Class.
We considered allowing the class-wide first parameter to be included if the type of the first parameter covers T. But that introduced a number of issues:
Essentially, a class-wide operation is inherited as-is, and cannot be changed for the inheriting type. It’s confusing to allow an aspect declaration that appears that it can be changed.
It’s also the case that using a class-wide operation for indexing is very unfriendly from an OOP perspective. Doing so means that no descendant can ever change the indexing operation. It is the height of hubris to assume that no one ever will need to do that, even people solving problems that have not yet been thought of. That can be OK for peripheral operations (especially those in separate units), as those can easily be replaced if needed. But a fundamental operation like indexing is not so easily replaced without effects to all uses (one cannot change the "name" of the actual indexing operation, it is always parentheses following some appropriate object name).
So while it is important that we aren’t rejecting extensions just because a class-wide operation is used somewhere, it is less important that we allow more than that. Adding several complications to the rules just to support inherited class-wide operations seems like a lot of work for a marginal case.
See !Issue.
@drepl
@xhang{@xterm{Constant_Indexing}This aspect shall be specified by a @fa{name} that denotes one or more functions declared immediately within the same declaration list in which @i{T}, or the declaration completed by @i{T}, is declared. The expected profile of this aspect is any function. All such functions shall have at least two parameters, the first of which is of type @i{T} or @i{T}'Class, or is an access-to-constant parameter with designated type @i{T} or @i{T}'Class.}
@dby
@xhang{@xterm{Constant_Indexing}This aspect shall be specified by a @fa{name} that denotes one or more functions. When directly specified, the expected profile of this aspect is satisfied by every function that has at least two parameters, the first of which is of type @i{T} or, if @i{T} is a tagged type, @i{T}'Class, or is an access parameter designating one of these types. If the first parameter of such a function is an access parameter, it shall be an access-to-constant parameter.}
@drepl
@xhang{@xterm{Variable_Indexing}This aspect shall be specified by a @fa{name} that denotes one or more functions declared immediately within the same declaration list in which @i{T}, or the declaration completed by @i{T}, is declared. The expected profile of this aspect is any function. All such functions shall have at least two parameters, the first of which is of type @i{T} or @i{T}'Class, or is an access parameter with designated type @i{T} or @i{T}'Class. All such functions shall have a return type that is a reference type (see @ref{4.1.5}), whose reference discriminant is of an access-to-variable type.}
@dby
@xhang{@xterm{Variable_Indexing}This aspect shall be specified by a @fa{name} that denotes one or more functions. When directly specified, the expected profile of this aspect is satisfied by every function that has at least two parameters, the first of which is of type @i{T} or, if @i{T} is a tagged type, @i{T}'Class, or is an access parameter designating one of these types. All such functions shall have an explicitly aliased nonconstant result, or a return type that is a reference type (see @ref{4.1.5}), whose reference discriminant is of an access-to-variable type.}
@drepl
In certain contexts, such as in a @fa{subprogram_renaming_declaration}, the Name Resolution Rules define an @i{expected profile} for a given @fa{name}; in such cases, the @fa{name} shall resolve to the name of a callable entity whose profile is type conformant with the expected profile.
@dby
In certain contexts, such as in a @fa{subprogram_renaming_declaration}, the Name Resolution Rules define an @i{expected profile} for a given @fa{name}; in such cases, the @fa{name} shall resolve to the name of a callable entity whose profile is type conformant with the expected profile, or, where explicitly allowed, to one or more callable entities whose profiles satisfy the expected profile with respect to the required number and types of parameters, and, for a function, the type of the result.
@drepl
@xbullet{an aspect that denotes a subprogram, the @fa{aspect_definition} shall be a @fa{name}; the expected profile for the @fa{name} is the profile required for the aspect of the associated entity; additionally, unless otherwise specified, only subprograms declared within the declarative region of the entity associated with the aspect are considered;}
@dby
@xbullet{an aspect that denotes a subprogram, the @fa{aspect_definition} shall be a @fa{name}; the expected profile defined for the aspect imposes requirements on the profile of any subprogram that can be denoted by the aspect; additionally, unless otherwise specified, the only subprograms considered are nonformal subprograms declared within the same declarative region as that of the entity associated with the @fa{aspect_specification};}
Add a C test along the lines of the examples in the !issue section that checks that a package can declare multiple types specifying indexing aspects using the same names, and those aspects can be used in indexings that resolve to the appropriate functions. Existing ACATS tests should be modified or withdrawn to match these rules.
From: Randy Brukardt
Sent: Thursday, February 26, 2026
The wording changes unnecessarily inserted and deleted large sections of unchanged text. I reformatted them to show only the text that was actually changed. I did not intend to change the resulting text. Consider this part of my Editorial Review for this AI.
From: Randy Brukardt
Sent: Thursday, March 5, 2026
This AI has been reopened because of two issues. First, the approved wording for 4.1.6(3/3) conflicts with the wording approved for AI22-0075-1. That AI allows a variable indexing to return any type, so long as the return is aliased. Aliased is treated like a mode for resolution purposes (that is to say it isn’t used for resolution), so the return type in the profile needs to be essentially “any type”. The wording here said something different.
Second, not strictly related to this AI but in the wording here, we mention T’Class multiple times. But T can be any type (now, from AI22-0136-1), and we don’t want to talk about the nonexistent T’Class for untagged types. So some rewording is needed.
From: Randy Brukardt
Sent: Wednesday, March 11, 2026
A third issue was discovered by Gary Dismukes before this AI could go out for a vote. A class-wide subprogram is inherited by the aspect as-is for a derived type, but the recheck of Legality Rules arguably would fail because the denoted subprogram is not in the correct declaration list.
After much internal discussion, it was determined that the requirement for the same declaration list is no longer needed so long as the newly declared type that has the aspect is required to be a parameter of the operations. So that was removed, and the wording was again rearranged.
The following discussion on the proposed AARM note 4.1.6(3.c/6):
Ramification:When the aspect is not directly specified, it is inherited by the rules given in 13.1, and thus the expected profile is not used or needed. We include "When directly specified" to make that clear.
Occurred between March 12 and 17, 2026. It is being preserved here as it is not directly relevant to this AI (it is mainly associated with what is now AI22-0159-1).
Gary Dismukes:
This doesn't sound right to me. In the case of a derived type that inherits (non-class-wide) indexing functions, it's been my understanding that new (as well as overriding) indexing functions can be declared, and surely the expected profile is needed to validate such added functions. I believe the "When directly specified" wording came into the picture as a result of considering the case of inherited class-wide functions (in conjunction with the "declared immediately within the same declaration list" wording). But that seems to have broken the non-class-wide case. Or am I misunderstanding something here?
Randy Brukardt:
My understanding of the rules is that one only gets new functions if you include a confirming aspect (which indeed causes a new resolution, which is necessary to prove that it is confirming). Note that confirming here is not an exact match, but rather a match in that all of the existing inherited functions are included (that's in 13.1.1). Otherwise, the aspect only includes the inherited functions. That was not the original intent as I understood it, but it seems pretty clear to be the case given the 13.1 inheritance rules -- there is no re-resolution for the inheritance itself, and the only thing that could cause such resolution is an explicit aspect specification.
This seems like a point more related to the new AI than this one, so probably we should continue this there (once it exists).
Gary Dismukes:
FWIW, I understand your interpretation, but I find it quite surprising that a confirming aspect can have different semantics vs. the aspect being inherited. Seems like an unintended consequence.
BTW, note that your statement above that "Otherwise, the aspect only includes the inherited functions" isn't entirely accurate, as functions overriding the inherited ones will also be included (maybe what you meant).
In any case, OK to continue this in the other AI if that makes sense.
Tucker Taft:
I got started on that AI (AI22-0msp-1 in New AIs, but it isn't ready) and wrote the following:
"When a type-related aspect is allowed to denote multiple subprograms, and is also inherited, the rules for inheritance are clarified to say that nonprimitives cannot be overridden, and no additional primitive subprograms are considered for a derived type unless the aspect is directly specified for the derived type."
I think this rule is debatable, and whatever we decide might have an effect on the wording of AI22-0154-1, so we ultimately might end up putting the AIs back together. In any case, I'll write it up separately so we can debate it, and once we settle on the rules, we can come back and tweak the wording of this AI if necessary.
Tucker Taft:
Here is my new !summary from the "new" AI:
When a type-related aspect is allowed to denote multiple subprograms, and is also inherited, the rules for inheritance are clarified. In particular, if the aspect denotes one or more nonprimitive subprograms, they cannot be overridden. An aspect that denotes primitives follows a somewhat different rule. The subprograms denoted by such an aspect can be overridden, and any additional primitives of the same name, with multiple parameters and whose first parameter is of the type or an access parameter designating the type, are automatically included. This is not dependent on whether the aspect is confirmed.