Version 1.10 of ai05s/ai05-0071-1.txt

Unformatted version of ai05s/ai05-0071-1.txt version 1.10
Other versions for file ai05s/ai05-0071-1.txt

!standard 12.5.1(23.1/2)          08-10-22 AI05-0071-1/05
!standard 12.6(10)
!class binding interpretation 08-06-21
!status Amendment 201Z 08-11-26
!status WG9 Approved 08-10-31
!status ARG Approved 6-0-2 08-06-21
!status work item 07-10-24
!status received 07-10-05
!priority Medium
!difficulty Medium
!subject Class-wide operations for formal subprograms
!summary
An equivalence is defined for the purposes of formal subprogram default matching so that a similar substitution is made for the class-wide type as would be made for an inherited subprogram inside of the generic.
!question
There is no predefined equality operator for class-wide types. This causes a problem when instantiating predefined containers in that it is necessary to create a dispatching equality operation for this purpose:
function Equal(Left, Right : T'Class) return Boolean; package T_Vectors is new Ada.Containers.Indefinite_Vectors( Positive, T'Class, Equal);
Should this be fixed somehow? (Yes.)
!recommendation
(See summary.)
!wording
Modify 12.5.1(23.1/2):
In the case where a formal type [is tagged with] {has} unknown discriminants, and the actual type is a class-wide type T'Class:
Modify 12.6(10) as follows:
If a generic unit has a subprogram_default specified by a box, and the corresponding actual parameter is omitted, then it is equivalent to an explicit actual parameter that is a usage name identical to the defining name of the formal. {If a subtype_mark in the profile of the formal_subprogram_declaration denotes a formal private or formal derived type and the actual type for this formal type is a class-wide type T'Class, then for the purposes of resolving this default_name at the point of the instantiation, for each primitive subprogram of T that has a matching defining name, that is directly visible at the point of the instantiation, and that has at least one controlling formal parameter, a corresponding subprogram with the same defining name is directly visible, but with T systematically replaced by T'Class in the types of its profile. The body of such a subprogram is as defined in 12.5.1 for primitive subprograms of a formal type when the actual type is class-wide.}
!discussion
In developing a spec for the "tagged" version of the ASIS "Views" packages, there emerged an "interesting" annoyance with the Indefinite_Vectors container. Because it takes "=" as a formal subprogram parameter, if one instantiates it with a class-wide type, there is no "=" automatically available. It is necessary to explicitly declare an "Equal" function on the class-wide type, and pass it in. The body of the "Equal" function would simply make a dispatching call on the "=" for the corresponding specific type. Such as:
function Equal(Left, Right : T'Class) return Boolean; package T_Vectors is new Ada.Containers.Indefinite_Vectors( Positive, T'Class, Equal); function Equal(Left, Right : T'Class) return Boolean is begin return Left = Right; end Equal;
It is important not to actually name it "=" because if so named, it would create ambiguity at every call.
This all seems kind of annoying/surprising. Since one is allowed in an instantiation to provide a class-wide type if the formal type has unknown discriminants, and there are new rules for how the primitives of the formal type are to be defined in terms of the actuals (paras 23.1/2-23.3/2 of 12.5.1), it would seem to make sense for such operations to be available for formal subprograms with a "<>" default. Hence, we have proposed wording in 12.6 to allow for these operations, and to refer to 12.5.1 for the definition of the semantics of the body.
The change to the wording in 12.5.1(23.1/2) is to eliminate the word "tagged", because the formal need not be tagged for the actual to be class-wide, in the case of a formal private type with unknown discriminants.
The addition to the wording of 12.6 should allow instantiations with class-wide types to work as the user would expect. That is, by adding the following to a generic formal part:
with function "="(Left, Right : T)
return Boolean is <>;
we are simply trying to import any user-defined equality operator rather than having some underlying equality operator reemerge, while also making it clear that equality is important to the functioning of the generic. Unfortunately, as it is now, adding in this nice piece of functionality penalizes instantiations for which the actual is a class-wide type.
An alternative approach would be to change the rules for matching "expected profiles", which might imply having a new kind of conformance between profiles, such as "call conformance". That is "call conformance" would include the matching allowed between formal parameter types and actual parameter types in a call (8.6(20/2-25.1/2)). This would obviously be a bigger change, and we have chosen to go with the smaller change in this AI.
!example
generic type Priv(<>) is private;
X, Y : Priv;
with function "="(Left, Right : Priv) return Boolean is <>; package GP is Are_Equal : constant Boolean := (X = Y); -- use "=" end GP;
...
procedure Test(U, V : T'Class) is use type T; package P is new GP(T'Class, U, V); -- This instantiation should work, without -- our having to declare and pass in explicitly -- an equality operator for T'Class. But this -- is illegal without the changes. begin if P.Are_Equal then ... end if; end Test;
!corrigendum 12.5.1(23.1/2)
Replace the paragraph:
In the case where a formal type is tagged with unknown discriminants, and the actual type is a class-wide type T'Class:
by:
In the case where a formal type has unknown discriminants, and the actual type is a class-wide type T'Class:
!comment The changes to 12.6(10) were removed by AI05-0131-1.
!comment !corrigendum 12.6(10).
!comment
!comment @drepl
!comment If a generic unit has a @fa<subprogram_default> specified by a box, and the
!comment corresponding actual parameter is omitted, then it is equivalent to an explicit
!comment actual parameter that is a usage name identical to the defining name of the formal.
!comment @dby
!comment If a generic unit has a @fa<subprogram_default> specified by a box, and the
!comment corresponding actual parameter is omitted, then it is equivalent to an explicit
!comment actual parameter that is a usage name identical to the defining name of the formal.
!comment If a @fa<subtype_mark> in the profile of the
!comment @fa<formal_subprogram_declaration> denotes a formal private or formal derived
!comment type and the actual type for this formal type is a class-wide type
!comment @i<T>'Class, then for the purposes of resolving this @fa<default_name> at the
!comment point of the instantiation, for each primitive subprogram of @i<T> that has
!comment a matching defining name, that is directly visible at the point of the
!comment instantiation, and that has at least one controlling formal parameter,
!comment a corresponding subprogram with the same defining name is directly
!comment visible, but with @i<T> systematically replaced by @i<T>'Class in the types
!comment of its profile. The body of such a subprogram is as defined in
!comment 12.5.1 for primitive subprograms of a formal type when the actual
!comment type is class-wide.
!ACATS test
ACATS C-Test(s) are necessary for this change.
!ASIS
Add at the end of 12.45: - Ada Standard 12.6(10)
- The implicit subprogram that exists for class-wide types
corresponding to a defaulted formal subprogram is Is_Part_Of_Implicit. The enclosing element of their declaration is the enclosing element of the corresponding specific type.
!appendix

From: Tucker Taft
Date: Friday, October 5, 2007 11:21 AM

In developing a spec for the "tagged" version of the
ASIS "Views" packages, I ran into an "interesting"
annoyance with the Indefinite_Vectors container.  Because
it takes "=" as a formal subprogram parameter, if
one instantiates it with a class-wide type, there is
no "=" automatically available.  I had to explicitly
declare an "Equal" function on the class-wide type,
and pass it in.  The body of the "Equal" function would
simply make a dispatching call on the "=" for the
correspnding specific type.  E.g.:

     function Equal(Left, Right : T'Class) return Boolean;
     package T_Vectors is new
       Ada.Containers.Indefinite_Vectors(
         Positive, T'Class, Equal);

I also had to be sure I didn't actually name it "=" because
if I did so, I would create ambiguity at every call.

That seems kind of annoying/surprising.  Since we
now acknowledge the possibility of instantiating a
formal type with unknown discriminants with a class-wide
type, and have defined the rules for how the
primitives of the formal type are to be defined
in terms of the actuals (paras 23.1/2-23.3/2 of 12.5.1),
it would seem to make sense to also make such
operations available for formal subprograms
with a "<>" default.  This would imply adding another
paragraph after 23.3/2, something like:

   * If a primitive operation of T is directly visible
     at the point of the instantiation, then a subprogram
     with the same name, but with T systematically replaced
     by T'Class in formal parameter types and result types,
     is considered directly visible at the point of the
     instantiation, for the purpose of resolving the
     actual parameter for a formal subprogram with a
     subprogram_default specified by a box.  The body for
     such an operation, and controlling tag determination
     for such an operation, is as defined above.

Although this a bit of a mouthful, I believe it is reasonable
if we are trying to allow instantiations with class-wide
types to work as the user would expect.  That is, by
adding in to a generic formal part:

    with function "="(Left, Right : T)
      return Boolean is <>;

we are simply trying to import any user-defined equality
operator rather than having some underlying equality
operator reemerge, while also making it clear that equality
is important to the functioning of the generic.  Unfortunately,
as it is now, adding in this nice piece of functionality
penalizes instantiations for which the actual is a class-wide type.

An alternative approach would be to change the rules for matching
"expected profiles," which might imply having a new kind of
conformance between profiles, such as "call conformance."  That
is "call conformance" would include the matching allowed between
formal parameter types and actual parameter types in a call
(8.6(20/2-25.1/2)).  This would obviously be a bigger change.

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



Questions? Ask the ACAA Technical Agent