AI22-0027-1

!standard 3.4.1(5)          22-06-23 AI22-0027-1/04

!standard 4.5.2(28.1/5)

!standard 12.5.1(23.2/2)

!standard 12.6(9.2/3)

!class binding interpretation 22-01-24

!status Amendment 1-2022 22-06-23

!status WG9 Approved 22-10-18

!status ARG Approved 15-0-0 22-06-23

!status work item 22-01-24

!status received 21-11-18

!submitter Tucker Taft

!priority Low

!difficulty Easy

!qualifier Omission

!subject Primitive equality of a class-wide type

!summary

The primitive equality of a class-wide type T'Class is implemented by a dispatching call on the primitive equality of T.

!issue

What is the "primitive equality" for a class-wide type? This term is used in 4.5.2(28.1/5) describing the semantics of membership, where it says:

... If the tested type is a record type or a record extension, or is limited at the point where the membership test occurs, the test uses the primitive equality for the type; otherwise, the test uses predefined equality. ...

If the tested type is a class-wide type, we need to call the primitive equality of the class-wide type. But 3.4.1(5) says that class-wide types have no primitive subprograms of their own. So what is called here??

!recommendation

(See Summary.)

!wording

Add after 3.4.1(5):

When a language rule references a given primitive operation of a type, in the case of a class-wide type T'Class, this is equivalent to a subprogram (with an intrinsic calling convention — see 6.3.1) whose body consists of a dispatching call upon the corresponding operation of T, with its formal parameters as the actual parameters. If it is a function, the result of the dispatching call is returned.

Add after AARM 4.5.2(28.a/5):

AARM Ramification: If the tested type is class-wide, "primitive equality" is interpreted as described in 3.4.1. Specifically, it is implemented by a dispatching call on the primitive equality of the specific type associated with the class-wide type.

[Editor's note: The following modifications are to take existing explicit descriptions and change them to depend on the general description now added to 3.4.1.]

Modify 12.5.1(23.2/2):

Modify 12.6(9.2/3):

For each primitive subprogram of T that is directly visible at the point of the instantiation, and that has at least one controlling formal parameter, a corresponding implicitly declared subprogram with the same defining name, and having the same profile as the primitive subprogram except that T is systematically replaced by T'Class in the types of its profile, is potentially use-visible. The body of such a subprogram is as defined in {3.4.1}[12.5.1] for primitive subprograms of a [formal type when the actual type is ]class-wide{ type}.

!discussion

We would expect that the primitive equality for a class-wide type is implemented by a dispatching call on the primitive equality for the root of the class-wide type. Since 3.4.1(5) says that a class-wide type does not have primitive operations, a user-defined equality cannot be a primitive equality. So if we have a function like:

function "=" (Left, Right : T'Class) return Boolean;

This function has no effect on the semantics of membership.

This is consistent with how class-wide types are treated when used as the actual type for a formal tagged type in a generic instance -- see 12.5.1(23.1/2 - 23.2/2):

In the case where a formal type has unknown discriminants, and the actual type is a class-wide type T'Class:

!corrigendum 3.4.1(5)

@dinsa
@xindent{The set of values for a class-wide type @i{T}'Class is the
discriminated union of the set of values of each specific type in the
derivation class rooted at @i{T} (the tag acts as the implicit discriminant
@emdash see @ref{3.9}). Class-wide types have no primitive subprograms of their own.
However, as explained in @ref{3.9.2}, operands of a class-wide type @i{T}'Class can
be used as part of a dispatching call on a primitive subprogram of the type
@i{T}. The only components [(including discriminants)] of @i{T}'Class that are
visible are those of @i{T}. If S is a first subtype, then S'Class is a first
subtype.}
@dinst
@xindent{When a language rule references a given primitive operation of a type,
in the case of a class-wide type @i{T}'Class, this is equivalent to a
subprogram (with an intrinsic calling convention @emdash see @ref{6.3.1}) whose body
consists of a dispatching call upon the corresponding operation of @i{T}, with
its formal parameters as the actual parameters. If it is a function, the
result of the dispatching call is returned.}

!corrigendum 12.5.1(23.2/2)

@drepl
@xbullet{For the purposes of defining the primitive operations of the formal
type, each of the primitive operations of the actual type is considered to be
a subprogram (with an intrinsic calling convention @emdash see @ref{6.3.1}) whose
body consists of a dispatching call upon the corresponding operation of @i{T},
with its formal parameters as the actual parameters. If it is a function, the
result of the dispatching call is returned.}
@dby
@xbullet{For the purposes of defining the primitive operations of the formal
type, each of the primitive operations of the actual type is considered to be
a subprogram as described in @ref{3.4.1} for primitive operations of a class-wide
type.}

!corrigendum 12.6(9.2/3)

@drepl
@xindent{For each primitive subprogram of @i{T} that is directly visible at
the point of the instantiation, and that has at least one controlling formal
parameter, a corresponding implicitly declared subprogram with the same
defining name, and having the same profile as the primitive subprogram except
that @i{T} is systematically replaced by @i{T}'Class in the types of its
profile, is potentially use-visible. The body of such a subprogram is as
defined in @ref{12.5.1} for primitive subprograms of a formal type when the actual
type is class-wide.}
@dby
@xindent{For each primitive subprogram of @i{T} that is directly visible at
the point of the instantiation, and that has at least one controlling formal
parameter, a corresponding implicitly declared subprogram with the same
defining name, and having the same profile as the primitive subprogram except
that @i{T} is systematically replaced by @i{T}'Class in the types of its
profile, is potentially use-visible. The body of such a subprogram is as
defined in @ref{3.4.1} for primitive subprograms of a class-wide type.}

!ACATS test

An ACATS C-Test is needed to ensure that the correct equality is called for a membership. It should try a case with a user-defined equality as noted above.

!appendix

From: Tucker Taft

Sent: Thursday, November 18, 2021 7:28 AM

What is the "primitive equality" for a class-wide type? This question came up

recently, regarding the wording in 4.5.2(28.1/5) describing the semantics of

membership, where it says:

  ... If the tested type is a record type or a record extension, or is

  limited at the point where the membership test occurs, the test uses the

  primitive equality for the type; otherwise, the test uses predefined

  equality. ...

If the tested type is a class-wide type, the wording is a bit confusing.

Presumably the primitive equality for a class-wide type is defined by a

dispatching call on the primitive equality for the root of the class-wide

type. In particular, if there is a user-defined equality on the class-wide

type:

  function "=" (Left, Right : T'Class) return Boolean;

that is completely ignored. It has no effect on the semantics of membership.

Perhaps we should define this notion of the "primitive equality of a

class-wide type," or adjust the wording to accommodate this special case.

I could see adjusting RM 3.4.1(5) as follows:

  The set of values for a class-wide type T'Class is the discriminated union

  of the set of values of each specific type in the derivation class rooted

  at T (the tag acts as the implicit discriminant — see 3.9). Class-wide

  types have no primitive subprograms of their own. However, as explained in

  3.9.2, operands of a class-wide type T'Class can be used as part of a

  dispatching call on a primitive subprogram of the type T. {When a language

  rule references a given primitive operation of a type, in the case of a

  class-wide type T'Class, this is to be interpreted as a dispatching call

  on the corresponding primitive operation of T.} The only components

  [(including discriminants)] of T'Class that are visible are those of T. If

  S is a first subtype, then S'Class is a first subtype.

This is consistent with how class-wide types are treated when used as the

actual type for a formal tagged type in a generic instance -- see

12.5.1(23.1/2 - 23.2/2):

  In the case where a formal type has unknown discriminants, and the actual

  type is a class-wide type T'Class:

   * For the purposes of defining the primitive operations of the formal

     type, each of the primitive operations of the actual type is

     considered to be a subprogram (with an intrinsic calling convention —

     see 6.3.1) whose body consists of a dispatching call upon the

     corresponding operation of T, with its formal parameters as the actual

     parameters. If it is a function, the result of the dispatching call is

     returned.

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