Version 1.2 of ais/ai-00200.txt

Unformatted version of ais/ai-00200.txt version 1.2
Other versions for file ais/ai-00200.txt

!standard 03.02.03 (07)          99-03-14 AI95-00200/01
!class binding interpretation 98-03-27
!status work item 99-03-14
!status received 98-03-27
!priority Low
!difficulty Medium
!subject Generic formal subprograms as dispatching operations
!summary 99-03-14
generic formal subprograms are never primitive operations and hence cannot be dispatching operations, even though they can potentially override an implicitly declared primitive operation of a formal type. The primitive operations of a formal type comprise only the predefined operators and implicitly declared subprograms of the formal type.
!question 99-03-14
The definition of primitive subprograms in 3.2.3(7) suggests that the copies of generic formal subprograms in an instance can be dispatching operations if they override any implicitly declared primitive subprograms there. It is unclear how dispatching calls on such subprograms should be performed.
For example:
package P is type Root is tagged ... -- implicit "="(left, right : Root) return boolean; function Foo (l,r : Root) return boolean; end P; use P;
generic type T is new Root with private; -- implicit "="(left, right : T) return boolean; -- (1) -- implicit Foo(left, right : T) return boolean; -- (2) with function "="(l,r : T) returns boolean; -- (3) with function Foo(l,r : T) returns boolean; -- (4) package G is procedure Test (X : T'class); end G;
function Bar (l,r : Root) return boolean;
package I1 is new G(Root, "=", Foo); package I2 is new G(Root, Foo, "="); package I3 is new G(Root, Bar, Bar);
In each of the instances of G, the declaration of T declares a new view of Root by RM95 12.3(15). The predefined "=" operator (1) is copied and is considered primitive by RM95 12.5.1(21) and RM95 3.2.3(3). Likewise, the Foo function (2) is copied and is considered primitive by RM95 12.5.1(21) and RM95 3.2.3(4). The user-defined "=" operator (3) and Foo function (4) declare new views of the generic actual subprograms specified for each instance. The "=" (3) and Foo (4) operations are declared in the same declarative region as the predefined ones (1) and (2) and override them by RM95 8.3(10). So, it seems that it should be considered primitive, too, by RM95 3.2.3(7).
Because the "=" (3) and Foo (4) operations are primitive operations of (a view of) a tagged type in each of the instances, they should also be dispatching operations by RM95 3.9.2(1).
[It is not the intent that formal subprograms should ever be primitive operations of a type.]
Note that a similar problem exists for a formal subprogram overriding the primitive "=" operator of a formal tagged private type:
generic type T is new tagged private; -- implicit "="(left, right : T) return boolean; -- (1) with function "="(l,r : T) returns boolean; -- (3) package G is procedure Test (X : T'class); end G;
package body G is procedure Test (X : T'class) is begin ... := (X = X); -- [Illegal: "=" (3) is not dispatching] end Test; end G;
Is the formal function "=" a primitive operation of type T? [No.]
Also note that a similar problem exists for ordinary subprograms overriding primitive operations of a generic formal tagged private or generic formal derived tagged type:
generic type T is new Root with private; -- implicit "="(left, right : T) return boolean; -- (1) -- implicit Foo(left, right : T) return boolean; -- (2) package G is function "="(l,r : T) returns boolean; -- (3) function Foo(l,r : T) returns boolean; -- (4)
procedure Test (X : T'class); end G;
package body G is function "="(l,r : T) returns boolean is ... end "=";
function Foo(l,r : T) returns boolean is ... end Foo;
procedure Test (X : T'class) is begin ... := (X = X); -- [Illegal: "=" (3) is not dispatching] ... := Foo(X, X); -- [Illegal: Foo (4) is not dispatching] end Test; end G;
Are the declarations of "=" and Foo in the visible part of G primitive operations of the formal type T? [No.]
So, what subprograms should be executed for calls to the "=" (3) and Foo (4) operations in each of the calls to Test?
[The calls are illegal because the invoked subprograms are not dispatching operations.]
!recommendation 99-03-14
The rule given in 3.2.3(7) is not intended to apply to subprograms that override the implicitly declared primitive subprograms of a generic formal type. The only operations that are primitive subprograms of a formal type are the subprograms implicitly declared at the point of the formal type declaration.
In particular, a formal subprogram that overrides a primitive operation of a formal type is not a primitive operation of the type, and thus is not a dispatching operation of the type. Similarly, a subprogram declared immediately within the package specification of a generic formal package declaration and overrides a primitive operation of a formal type of the generic is not a primitive of the type, even though it occurs within the same declarative region as the formal type.
!wording 99-03-14
Revise 3.2.3(7) to make it clear that the rule does not apply to generic formal types, e.g.:
"{In the case of a nonformal type,} any subprograms not covered above that are explicitly declared immediately within the same declarative region as the type and that override (see 8.3) other implicitly declared primitive subprograms of the type."
!discussion 99-03-14
The principal question asked by the submitter is whether formal subprograms can ever be dispatching operations of a formal type. In particular, when a formal subprogram overrides an inherited subprogram of a formal derived tagged type, is it defined to be a primitive operation of the formal type and thus can it be called with dynamically typed operands? The current wording of 3.2.3(7) seems to imply that such a formal subprogram is a primitive of the formal type, because it satisfies the requirements of being declared immediately within the same declarative region as the formal type (8.1) and of overriding an implicitly declared primitive subprogram of the type (8.3(10)).
However, it was never the intent that formal subprograms should ever treated as primitive operations of a formal type. In fact, the primitive operations for formal nonderived types are explicitly defined by 12.5(8) to be the predefined operators of the type, and hence could not include, for example, an overriding "=" function. The definition of the primitives for a formal derived type are not as clearly defined (12.5.1(21)), but it also would not make sense to include overriding formal subprograms in a formal derived type's set of primitives.
in fact, to treat overriding formal subprograms as primitives for a formal tagged type would be inconsistent with the dispatching model. For example, if the actual subprogram associated with an overriding formal subprogram in an instance were not even a primitive of the actual type (as for one of the instantiations in the examples of the
!question section), then it would not be sensible for this actual
subprogram to suddenly become a dispatching primitive simply because it was used in an instantiation. How would the actual subprogram be incorporated into the dispatch table of the actual type, and what would it even mean to have two subprograms associated with the same dispatch table entry?
The submitter also raises a similar question for the situation where primitives of a formal type are overridden by subprograms declared in the specification of a formal package. By 3.2.3(7) it would appear that the overriding subprograms become primitives of the formal type since the subprograms are declared immediately within the same declarative region as the formal type. Again, it was not the intent that such overriding operations should become primitives of a formal type.
Note that even though the implicitly declared primitive subprograms of a formal type can be overridden, this does not mean that an overriding operation is a primitive of the type, even though that is normally the case for overridings of operations of nonformal types. In particular, this means that a derivation from the formal type will not inherit such overriding operations, but as usual will inherit the primitives of the formal type, even though some of them may be hidden at the point of derivation.
The fix for this wording problem is simply to specify that the rule of 3.2.3(7) only applies to nonformal types.
!appendix

!section 3.2.3(7)
!subject Generic formal subprograms as dispatching operations
!reference RM95-3.2.3(7)
!reference RM95-12.5.1(21)
!reference RM95-12.3(15-16)
!reference RM95-8.3(10)
!reference RM95-3.9.2(1,20)
!reference RM95-8.5.4(12)
!from Todd Allen 98-02-19
!keywords generic formal subprogram, primitive, dispatching
!reference 1998-15801.a Todd Allen 1998-2-19>>
!discussion

The definition of primitive subprograms in 3.2.3(7) suggests that the copies
of generic formal subprograms in an instance can be dispatching operations if
they override any implicitly declared primitive subprograms there.  It is
unclear how dispatching calls on such subprograms should be performed.

For example:

   package P is
      type Root is tagged ...
      -- implicit "="(left, right : Root) return boolean;
      function Foo (l,r : Root) return boolean;
   end P;
   use P;

   generic
      type T is new Root with private;
      -- implicit "="(left, right : T) return boolean;      -- (1)
      -- implicit Foo(left, right : T) return boolean;      -- (2)
      with function "="(l,r : T) returns boolean;           -- (3)
      with function Foo(l,r : T) returns boolean;           -- (4)
   package G is
      procedure Test (X : T'class);
   end G;

   function Bar (l,r : Root) return boolean;

   package I1 is new G(Root, "=", Foo);
   package I2 is new G(Root, Foo, "=");
   package I3 is new G(Root, Bar, Bar);

In each of the instances of G, the declaration of T declares a new view of
Root by RM95 12.3(15).  The predefined "=" operator (1) is copied and is
considered primitive by RM95 12.5.1(21) and RM95 3.2.3(3).  Likewise, the Foo
function (2) is copied and is considered primitive by RM95 12.5.1(21) and
RM95 3.2.3(4).  The user-defined "=" operator (3) and Foo function (4)
declare new views of the generic actual subprograms specified for each
instance.  The "=" (3) and Foo (4) operations are declared in the same
declarative region as the predefined ones (1) and (2) and override them by
RM95 8.3(10).  So, it seems that it should be considered primitive, too, by
RM95 3.2.3(7).

Brief Digression:

   The text in RM95 3.2.3(7) and the text throughout RM95 3.9.2 refer to
   types and subprograms as opposed to views of types and views of
   subprograms.  I have assumed that this was for purposes of brevity.  Many
   of the issues discussed herein also exist for renaming declarations.
   There is a note in RM95 8.5.4(12) which mentions that primitiveness is
   determined by the location of the renaming-as-declaration, as for any
   declaration of (a view of) a subprogram.  This suggests that the "a view
   of" text was intended throughout RM95 3.2.3 and RM95 3.9.2.

Because the "=" (3) and Foo (4) operations are primitive operations of (a
view of) a tagged type in each of the instances, they should also be
dispatching operations by RM95 3.9.2(1).

It is unclear what the effect would be of a dispatching call from within an
instance of G to the "=" (3) or Foo (4) operations.  For example, consider:

   package body G is
      procedure Test (X : T'class) is
      begin
         ... := (X = X);
         ... := Foo(X, X);
      end Test;
   end G;

   ...

   package Q is
      type Extension is new Root with ...;
      -- implicit "="(left, right : Extension) return boolean;
      -- implicit Foo(left, right : Extension) return boolean;
      function Foo (l,r : Extension) return boolean;
   end Q;
   use Q;

   ...

   I1.Test(Extension'(...));
   I2.Test(Extension'(...));
   I3.Test(Extension'(...));

During the execution of I3.Test, the calls to "=" (3) and Foo (4), which are
both views of Bar, should execute the bodies of their corresponding primitive
subprograms of type Extension.  But neither "=" (3) nor Foo (4) nor Bar has a
corresponding primitive subprogram of type Extension.

This confusion throws into doubt the meaning of RM95 3.9.2(20) with respect
to the "=" (3) and Foo (4) operations in I1 and I2, as well.  If the "a view
of" text was intended throughout this paragraph, then the meaning of the
corresponding primitive subprograms of the "=" (3) and Foo (4) operations
becomes unclear in I1.Test and I2.Test.  If the "a view of" text was not
intended there, then presumably the corresponding subprogram of the generic
actual subprogram would be used.  However, this still would not explain what
body should be called in the execution of I3.Test.

Note that a similar problem exists for a formal subprogram overriding the
primitive "=" operator of a formal tagged private type:

   generic
      type T is new tagged private;
      -- implicit "="(left, right : T) return boolean;      -- (1)
      with function "="(l,r : T) returns boolean;           -- (3)
   package G is
      procedure Test (X : T'class);
   end G;

   package body G is
      procedure Test (X : T'class) is
      begin
         ... := (X = X);
      end Test;
   end G;

Also note that a similar problem exists for ordinary subprograms overriding
primitive operations of a generic formal tagged private or generic formal
derived tagged type:

   generic
      type T is new Root with private;
      -- implicit "="(left, right : T) return boolean;      -- (1)
      -- implicit Foo(left, right : T) return boolean;      -- (2)
   package G is
      function "="(l,r : T) returns boolean;                -- (3)
      function Foo(l,r : T) returns boolean;                -- (4)

      procedure Test (X : T'class);
   end G;

   package body G is
      procedure Test (X : T'class) is
      begin
         ... := (X = X);
         ... := Foo(X, X);
      end Test;
   end G;

So, what subprograms should be executed for calls to the "=" (3) and Foo (4)
operations in each of the calls to Test?

--
Todd Allen
Concurrent Computer Corporation
Fort Lauderdale, FL  33309

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

!section 3.2.3(7)
!subject Generic formal subprograms as dispatching operations
!reference RM95-3.2.3(7)
!reference RM95-12.5.1(21)
!reference RM95-12.3(15-16)
!reference RM95-8.3(10)
!reference RM95-3.9.2(1,20)
!reference RM95-8.5.4(12)
!reference 1998-15801.a Todd Allen 98-02-19
!from Tucker taft 98-02-26
!keywords generic formal subprogram, primitive, dispatching
!reference 1998-15806.a Tucker Taft 1998-2-26>>
!discussion

: The definition of primitive subprograms in 3.2.3(7) suggests that the copies
: of generic formal subprograms in an instance can be dispatching operations if
: they override any implicitly declared primitive subprograms there.

This paragraph was not intended to apply to formal subprograms; some
wording improvement is in order.  In any case, the rules for tagged
types are constructed so that where a call on a dispatching subprogram goes is
independent of the location of the call, and is determined entirely
by which conceptual "slot" the specified dispatching operation
occupies.  The rules for calls on primitives of untagged types are
not based on a run-time "slot" but rather on the normal compile-time
visibility rules.  [This is implied by 3.9.2(14,20).  See also
AARM 3.9.2(20.a-20.g).]

The primitive subprograms of a formal type are specified in 12.5(8)
and 12.5.1(21); formal subprograms are not primitive subprograms, even
if they hide primitives of the formal type.

: Brief Digression:

:    The text in RM95 3.2.3(7) and the text throughout RM95 3.9.2 refer to
:    types and subprograms as opposed to views of types and views of
:    subprograms.  I have assumed that this was for purposes of brevity.

Which primitives of a type are visible are determined by of the corresponding
(implicit or explicit) subprogram declarations are visible.
It does not depend on which "view" of the *type* is being used, though
the two might be related because the implicit subprogram declarations
generally happen at the same point as the type declaration (though
not always!).

: ... Many
:    of the issues discussed herein also exist for renaming declarations.
:    There is a note in RM95 8.5.4(12) which mentions that primitiveness is
:    determined by the location of the renaming-as-declaration, as for any
:    declaration of (a view of) a subprogram.  This suggests that the "a view
:    of" text was intended throughout RM95 3.2.3 and RM95 3.9.2.

Yes, that is probably true for the subprograms.  It is not necessary
to insert "a view of" when referring to types.

: Because the "=" (3) and Foo (4) operations are primitive operations of (a
: view of) a tagged type in each of the instances, they should also be
: dispatching operations by RM95 3.9.2(1).

Formal subprograms are not primitives.

: ...

: So, what subprograms should be executed for calls to the "=" (3) and Foo (4)
: operations in each of the calls to Test?

As mentioned above, the rules for calls on dispatching operations are such
that compile-time view is irrelevant.  All that matters is what address
ends up in the "slot" at run-time, and that does not change based on
compile-time view.

: --
: Todd Allen
: Concurrent Computer Corporation
: Fort Lauderdale, FL  33309

--
-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Burlington, MA  USA

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

!section 3.2.3(7)
!subject Generic formal subprograms as dispatching operations
!reference RM95-3.2.3(7)
!reference RM95-12.5.1(21)
!reference RM95-12.3(15-16)
!reference RM95-8.3(10)
!reference RM95-3.9.2(1,20)
!reference RM95-8.5.4(12)
!reference 1998-15801.a Todd Allen 98-02-19
!from Todd Allen 98-02-26
!keywords generic formal subprogram, primitive, dispatching
!reference 1998-15807.a Todd Allen 1998-2-26>>
!discussion

Tucker,

   Thank you for your quick response to this comment.

>
> This paragraph [3.2.3(7)] was not intended to apply to formal
> subprograms; some wording improvement is in order.  In any case, the
> rules for tagged types are constructed so that where a call on a
> dispatching subprogram goes is independent of the location of the
> call, and is determined entirely by which conceptual "slot" the
> specified dispatching operation occupies.  The rules for calls on
> primitives of untagged types are not based on a run-time "slot" but
> rather on the normal compile-time visibility rules.  [This is
> implied by 3.9.2(14,20).  See also AARM 3.9.2(20.a-20.g).]
>

   This is the answer that I was expecting, and is in fact the interpretation
   that we've implemented.  I agree that the wording needs a little work to
   explicitly exclude formal subprograms as primitives.

>
> The primitive subprograms of a formal type are specified in 12.5(8)
> and 12.5.1(21); formal subprograms are not primitive subprograms, even
> if they hide primitives of the formal type.
>
> Which primitives of a type are visible are determined by of the corresponding
> (implicit or explicit) subprogram declarations are visible.
> It does not depend on which "view" of the *type* is being used, though
> the two might be related because the implicit subprogram declarations
> generally happen at the same point as the type declaration (though
> not always!).
>
> Yes, that is probably true for the subprograms.  It is not necessary
> to insert "a view of" when referring to types.
>

   I agree that the primitives of formal types are well-defined.

   My reason for believing that the "a view of" text was necessary for types
   as well as subprograms turns out to be faulty.  But I still have an issue
   on which I would appreciate some clarification, so I will explain.

   In the instance, the formal type declares a new view of the actual type,
   and the implicit subprograms of the formal type declare new views of the
   primitives of the actual type.  Because the implicit subprograms are new
   views, I believe that primitiveness has to be determined for them
   independently via the rules in 3.2.3(2-7) rather than the on the basis of
   the subprograms of which they are views (rather like subprogram renaming
   declarations).  Upon rereading 3.2.3(2-7), I notice that even if the "a
   view of" text was inserted for types into that section, the implicit
   subprograms in the instance would still not be considered primitive
   (because the view of the type would not be in a package_specification).

   So, how are the implicit subprograms in an instance considered primitive?
   Is it simply because they are copies of the primitives of the formal type?
   Is primitiveness an aspect that is copied from the implicit declarations
   in the generic to the implicit declarations of the instance?

>
> As mentioned above, the rules for calls on dispatching operations are such
> that compile-time view is irrelevant.  All that matters is what address
> ends up in the "slot" at run-time, and that does not change based on
> compile-time view.
>

   Am I correct in assuming that even though the formal subprograms are not
   considered primitive operations, they still override the primitive
   operations for visibility purposes?  This would mean that the formal
   subprograms would be called (in a non-dispatching manner) instead of their
   dispatching counterparts.

   So, in the example in my comment, for calls to Test in each of the
   instances of G, the calls to "=" and Foo would be non-dispatching calls to
   the actual subprograms associated with the formal subprograms.  Is this
   correct?

--
Todd Allen
Concurrent Computer Corporation
Fort Lauderdale, FL  33309

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

!section 3.2.3(7)
!subject Generic formal subprograms as dispatching operations
!reference RM95-3.2.3(7)
!reference RM95-12.5.1(21)
!reference RM95-12.3(15-16)
!reference RM95-8.3(10)
!reference RM95-3.9.2(1,20)
!reference RM95-8.5.4(12)
!reference 1998-15801.a Todd Allen 98-02-19
!reference 1998-15806.a Tucker Taft 98-02-26
!reference 1998-15807.a Todd Allen 98-02-26
!keywords generic formal subprogram, primitive, dispatching
!reference 1998-15808.a Tucker Taft 1998-2-26>>
!discussion

> ...
>    In the instance, the formal type declares a new view of the actual type,
>    and the implicit subprograms of the formal type declare new views of the
>    primitives of the actual type.  Because the implicit subprograms are new
>    views, I believe that primitiveness has to be determined for them
>    independently via the rules in 3.2.3(2-7) rather than the on the basis of
>    the subprograms of which they are views (rather like subprogram renaming
>    declarations).  Upon rereading 3.2.3(2-7), I notice that even if the "a
>    view of" text was inserted for types into that section, the implicit
>    subprograms in the instance would still not be considered primitive
>    (because the view of the type would not be in a package_specification).
>
>    So, how are the implicit subprograms in an instance considered primitive?
>    Is it simply because they are copies of the primitives of the formal type?
>    Is primitiveness an aspect that is copied from the implicit declarations
>    in the generic to the implicit declarations of the instance?

Primitiveness is generally only important for calls on dispatching
operations and when type derivation takes place.
It is certainly the intent that calls on the implicitly declared
primitives of the formal become calls on dispatching operations
if the actual type is tagged.
As far as type derivation, in the instance, deriving from a formal
becomes equivalent to deriving from the actual, which means that
in the instance, you might actually end up with more implicit
declarations.  This is explained in 12.3(16-17).

> > As mentioned above, the rules for calls on dispatching operations are such
> > that compile-time view is irrelevant.  All that matters is what address
> > ends up in the "slot" at run-time, and that does not change based on
> > compile-time view.
> >
>
>    Am I correct in assuming that even though the formal subprograms are not
>    considered primitive operations, they still override the primitive
>    operations for visibility purposes?  This would mean that the formal
>    subprograms would be called (in a non-dispatching manner) instead of their
>    dispatching counterparts.

Yes.

>    So, in the example in my comment, for calls to Test in each of the
>    instances of G, the calls to "=" and Foo would be non-dispatching calls to
>    the actual subprograms associated with the formal subprograms.  Is this
>    correct?

I don't have your example in front of me, but that sounds right.

> --
> Todd Allen
> Concurrent Computer Corporation
> Fort Lauderdale, FL  33309

-Tuck

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

Questions? Ask the ACAA Technical Agent