Version 1.4 of ais/ai-00200.txt

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

!standard 03.02.03 (07)          04-05-21 AI95-00200/03
!class binding interpretation 98-03-27
!status Amendment 200Y 04-03-24
!status ARG Approved 9-0-0 04-03-05
!status work item 99-03-14
!status received 98-03-27
!priority Low
!difficulty Medium
!subject Generic formal subprograms as dispatching operations
!summary
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
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) return Boolean; -- [3] with function Foo(l,r : T) return 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 12.3(15). The predefined "=" operator [1] is copied and is considered primitive by 12.5.1(21) and 3.2.3(3). Likewise, the Foo function [2] is copied and is considered primitive by 12.5.1(21) and 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 8.3(10). So, it seems that they should be considered primitive, too, by 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 3.9.2(1).
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) return 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) return Boolean; -- [3] function Foo (L, R : T) return Boolean; -- [4]
procedure Test (X : T'Class); end G;
package body G is function "=" (L, R : T) return Boolean is ... end "=";
function Foo (L, R : T) return 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?
!recommendation
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
Revise 3.2.3(7) to make it clear that the rule does not apply to generic formal types:
{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
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 be 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.
!corrigendum 3.2.3(07)
Replace the paragraph:
by:
!ACATS Test
Tests covering cases like those in the examples should be created.
!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

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

From: Randy Brukardt
Sent: Tuesday, March 16, 2004  5:43 PM

Someone posted the following program on comp.lang.ada:

package Pkg1 is
   type T_Event is abstract tagged null record;
   function Priority (Event : T_Event) return Natural is abstract;
end Pkg1;

-- ---------------------------------------------------------------
with Pkg1;
generic
   type T_Event (<>) is new Pkg1.T_Event with private;
package Pkg2 is
   function Priority (Event : in T_Event) return Natural;

   -- OK for GNAT 3.16a (20030120)
   -- KO for ObjectAda (tm) Version 7.2.1 :
   --
   --      7    function Priority (Event : in T_Event) return Natural;
   --                    *
   --  *****Error: LRM:3.9.2(13) a primitive subprogram of a tagged type may
not be
   --  *****        declared after the type is frozen

end Pkg2;

---

This seems to show a language hole (or, at least what will be a hole if
AI-359 is adopted).

The inherited Priority routine is primitive by 3.2.3. 8.3 then says that the
new declaration overrides it. Of course, this is bogus, because the type is
not even declared in this scope, so any such overriding has to be illegal -
it can't be implemented. But I can't find any reason for that. OA says that
the type is frozen, but there really isn't any reason to assume that (and
AI-359 would certainly make that not true in some cases). Even if the type
was not frozen, we'd still want this to be illegal.

So I don't see why this is illegal, but it's clear that it ought to be.

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

From: Adam Beneschan
Sent: Tuesday, March 16, 2004  6:26 PM

I'm somewhat confused.  Suppose you declare another package that
instantiates Pkg2:

with Pkg1, Pkg2;
package Pkg3 is
   type U_Event is new Pkg1.T_Event with null record;
   -- Implicitly declares the following:
   -- function Priority (Event : U_Event) return Natural is
   --    <shall-be-overridden>;
   package New_Pkg2 is new Pkg2 (U_Event);
end Pkg3;

The way generics work, it should be equivalent to this:

with Pkg1, Pkg2;
package Pkg3_Equivalent is
   type U_Event is new Pkg1.T_Event with null record;
   -- Implicitly declares the following:
   -- function Priority (Event : U_Event) return Natural is   --[A]
   --    <shall-be-overridden>;
   package New_Pkg2 is
      function Priority (Event : in U_Event) return Natural;  --[B]
   end New_Pkg2;
end Pkg3_Equivalent;

and the function marked [B] is not in the same declarative region as
the declaration of U_Event, so it's not a primitive subprogram of
U_Event, and there's no overriding, and no reason anything should be
illegal.  Neither 3.2.3 nor 8.3(9-13) would apply.  [8.3(13) appears
to apply only to a derived types and associated implicit subprograms
declared *in* the package spec, not to generic formal derived types
nor their inherited programs declared in the generic formal part.]

Perhaps the definition of "declarative region" is busted when it comes
to generics?  Looking at just the generic package:

    generic
       type T_Event (<>) is new Pkg1.T_Event with private;
    package Pkg2 is
       function Priority (Event : in T_Event) return Natural;  --[C]
    end Pkg2;

As with the Pkg3_Equivalent example, the declaration marked [C] is
*inside* the package Pkg2, while the type T_Event and any inherited
subprograms are *outside* the package.  At least that's what happens
when the package is instantiated, or what *should* happen.

It seems to me that a generic package such as the above ought to be
considered two declarative regions, with one including the entire
construct (including the formal part), and the second including the
entire construct excluding the generic formal part (and including the
package body), with the second one being considered an inner
declarative region.  Would this solve the problem?  Would this create
additional problems?  Is there something in the RM that already
accomplishes something like this?  I can't find it in 8.1.

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

From: Gary Dismukes
Sent: Tuesday, March 16, 2004  6:47 PM

I agree that the rules seem to allow this.  One way to fix it would
be to somehow change the overriding rules so that it's still legal
but doesn't override, but it seems like a bad idea to permit this
confusing declaration, so I agree that it should be made illegal.

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

From: Tucker Taft
Sent: Tuesday, March 16, 2004  8:07 PM

...
> This seems to show a language hole (or, at least what will be a hole if
> AI-359 is adopted).

I agree it is a whole, but it is one that has been there for a long
time, and it seems clear to me that:

  The explicit declaration is hiding from all visibility the primitive
  subprogram of the formal, but is *not* a primitive of the formal.

Consider the case:

    generic
        type T is private;
        with function "="(Left, Right : Boolean) return Boolean is <>;
    package Some_Generic is ...

This is a common paradigm, but we all "know" that the formal
function doesn't become a primitive subprogram as a result
of this construct, even though clearly it is hiding from
all visibility the implicitly defined "=" of the formal T.

So I think that 3.2.3(7) needs to say that such an overriding
does *not* produce a new primitive of a formal type.

The message from ObjectAda seems sort of reasonable if the
declaration were to create a new primitive, because the
*formal* seems clearly "frozen" (even if the actual might
not be by AI-359), but I think we should legislate against
making this a primitive.

> The inherited Priority routine is primitive by 3.2.3. 8.3 then says that the
> new declaration overrides it. Of course, this is bogus, because the type is
> not even declared in this scope, so any such overriding has to be illegal -
> it can't be implemented. But I can't find any reason for that. OA says that
> the type is frozen, but there really isn't any reason to assume that (and
> AI-359 would certainly make that not true in some cases). Even if the type
> was not frozen, we'd still want this to be illegal.
>
> So I don't see why this is illegal, but it's clear that it ought to be.

I'm not convinced, given the very common paradigm of having
formal subprograms that "override" predefined operators,
without becoming primitives.

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

From: Gary Dismukes
Sent: Wednesday, March 17, 2004  1:06 PM

Given what you pointed out about formal overriding, I now agree
that this should be allowed, and that this should be fixed by
changing the rules to make such overridings nonprimitve.

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

From: Randy Brukardt
Sent: Friday, March 19, 2004  2:09 PM

(* I've moved the following discussion from comp.lang.ada to here, so it is
on the permanent record *)

"Adam Beneschan" <adam@irvine.com> wrote (on comp.lang.ada):
> "Randy Brukardt" <randy@rrsoftware.com> wrote:

> > That's so that a type declared
> > in a body can have overriding routines, even though it can't have
> > primitives. Scopes have absolutely nothing to do with overriding (look at
> > 8.3 again if you don't believe me).
>
> Sorry, I looked at it and I still don't believe you.  8.3(9) says that
> a declaration can override another homograph if the declaration
> "occurs immediately within the same declarative region", etc.  The
> term "immediately within a declarative region" is defined by 8.1(13)
> and most definitely has to do with scopes.  If you declare a routine
> in a nested inner package, it cannot override a routine declared
> (implicitly or explicitly) in an outer package, because the routine in
> the inner package is not *immediately* declared in the same
> declarative region as the routine declared in the outer package.

The inherited routine *is* in this scope, because it belongs to and is
declared with the formal type (which is in this scope). When I said that
scopes don't matter, I was referring to the fact that the scope where the
inherited routine originally comes from isn't significant. That was a bad
choice of words.

In any case, both the inherited declaration and the explicit declaration are
in the scope of the generic spec. 8.3(9/1) says that the inherited
declaration is overridable.

> > Similarly, primitiveness has nothing to do with it.
>
> Primitiveness has nothing to do with whether a routine is overriding;
> but since the compiler in the original example reported an error
> because it thought the declared routine was primtive, it's certainly
> relevant to the problem.  Again, I'm probably just not understanding
> you correctly.

The compiler in the original example reported an error. The reason seems
bogus, but I didn't pay much attention to the reason reported; compilers
often give the wrong reason when reporting an error in a corner case. And
this certainly is a corner case.

> > I think it should be illegal simply because it is very confusing. This looks
> > like an overriding routine, but it is not.
>
> Now I'm convinced that I'm lost.  I thought you were disagreeing with
> me when I said the function (i.e. the Priority explicitly declared in
> the generic) is not an overriding routine?

I think everyone agrees that this *should not be* an overriding routine. (We
don't want retro-active overriding, which would require changing the tag.)
However, the current language wording says that it *is* an overriding
routine. I presume that we will fix the wording of the language so this is
not true.

The question is how to do this? My preference is to say that routines
inherited along with a formal type are not overridable. That makes this
example illegal, because you'd then have two homographs in the same scope.
(It's also the easiest wording change I can think of.)

Tucker suggests that this should be allowed, because the new operation is
not a primitive of the formal. I certainly agree that it is not primitive,
and the language already says that (a formal type is not declared
immediately in a package specification 3.2.3(6)). But it *still* is
overriding, because that has nothing to do with primitiveness (so that types
declared in scopes without primitive operations still have override
operations such as Finalize).

3.2.3(7) does say that overriding operations are primitive. And that's an
important rule in my view. Tucker seems to want to introduce a new kind
overriding that is not primitive. That's a significant change in a compiler;
I know that we don't have any separate indication of primitiveness in our
symboltable (it is deduced from the overriding state).

This minor language glitch does not seem significant enough to justify
forcing vendors to reorganize their symboltables (or worse, to cause them to
ignore the AI and its implications). Thus, I'd rather the construct be
illegal:
   -- To reduce user confusion;
   -- To prevent the need to have non-primitive overriding of tagged types
in compilers.

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

From: Tucker Taft
Sent: Friday, March 19, 2004  2:56 PM

> ...
> Tucker suggests that this should be allowed, because the new operation is
> not a primitive of the formal. I certainly agree that it is not primitive,
> and the language already says that (a formal type is not declared
> immediately in a package specification 3.2.3(6)). But it *still* is
> overriding, because that has nothing to do with primitiveness (so that types
> declared in scopes without primitive operations still have override
> operations such as Finalize).

I argued by analogy with something which is done
pretty frequently in Ada 95:

    generic
        type T is private;
        with function "="(Left, Right) return Boolean is <>;
    package ...

This seems almost exactly the same problem, except that the overriding
is even "closer" to the formal type, but *still* it doesn't become
a primitive.  If you derive from T, you should *not* get this formal
"=" subprogram.  You should get the implicitly declared one.
So this formal subprogram is *not* a primitive, even though it
hides from all visibility the implicitly declared "=",
since you cannot name this implicitly declared one, even using
expanded name notation.  If we don't want to call it overridden,
we could invent a new word, or just say it is hidden from all
visibility and leave it at that.

> 3.2.3(7) does say that overriding operations are primitive. And that's an
> important rule in my view. Tucker seems to want to introduce a new kind
> overriding that is not primitive. That's a significant change in a compiler;
> I know that we don't have any separate indication of primitiveness in our
> symboltable (it is deduced from the overriding state).
>
> This minor language glitch does not seem significant enough to justify
> forcing vendors to reorganize their symboltables (or worse, to cause them to
> ignore the AI and its implications). Thus, I'd rather the construct be
> illegal:
>    -- To reduce user confusion;
>    -- To prevent the need to have non-primitive overriding of tagged types
> in compilers.

I think you need to address the issue of formal subprograms that
hide implicitly declared primitives.  I personally believe that
subprograms declared in the visible part should have the same
rule as the formals declared in the formal part.  That is,
they can hide-from-all-visibility the implicitly declared primitive,
without becoming primitives.

I suppose the underlying model is that a formal type declaration
is really declaring a subtype, not a new type, and then implicitly
declaring renames of all the primitive subprograms.  Overriding these
renames with formal subprograms or subprograms declared in the
visible part doesn't make the new subprograms primitives, since
they are really just overriding renames of the primitives, not
the primitives themselves.

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

From: Adam Beneschan
Sent: Friday, March 19, 2004  8:05 PM

> The inherited routine *is* in this scope, because it belongs to and is
> declared with the formal type (which is in this scope). When I said that
> scopes don't matter, I was referring to the fact that the scope where the
> inherited routine originally comes from isn't significant. That was a bad
> choice of words.

OK, thanks for the explanation (and the one about the "primitive"
error message).  While we're discussing "bad choice of language", I
probably ought to point out that my original c.l.a post on the thread
was an attempt to summarize very briefly what I had previously said on
Ada-Comment, so there were probably important details left out.

I'd like to clarify my thinking on this issue:

   generic
       type T is new Root_T with private;
       -- procedure Operation (X : in T);  [implicitly inherited]
   package Pkg2 is
        procedure Operation (X : in T);
   end Pkg2;

The way I look at generics (and the way 12.3(13) seems to look at
them) is that when you instantiate, it's as if you declared a new copy
of the package at the point where you instantiate.  (Of course, some
compilers generate code that way and some don't, but that's not
relevant here.)  Thus, when you say something like "package New_Pkg2
is new Pkg2", it's as if you had declared a nested package New_Pkg2
and declared Operation inside it.  If you had done this, there would
be no way that this explicit Operation would be in the same scope as
the actual type and the inherited operation (they might not even be in
the same compilation unit).

My gut feeling on this is that, broadly, the language rules in effect
when the generic is compiled ought to parallel the language rules that
would be in effect when a copy of the template is made.  That's a
gross oversimplification, of course, since the same outer declarations
won't be visible in both places.  However, my gut feeling is that if
the language says that, IN THE GENERIC, T and the explicit Operation
are in the same scope, while in an instance this is not going to
happen, then there's something wrong with the language---since the
structure that the language is looking at when the generic is declared
is not "topologically equivalent" to the structure created when the
generic is instantiated.  OK, I realize this is quite vague.  I don't
know how to express this well.

But my conclusion from this is that the language is flawed if it says
that the formal type T and the explicit Operation are immediately in
the same declarative region.  It does seem to say this, as you say:

> In any case, both the inherited declaration and the explicit declaration are
> in the scope [of] the generic spec. 8.3(9/1) says that the inherited
> declaration is overridable.

but it doesn't seem right.  They should be in different scopes.

My previous Ada-Comment post suggested that the generic ought to be
considered two declarative regions, with the region starting at
"package Pkg2 is" (and including the body of Pkg2) should be
considered "inner" to the region that includes the generic formals
(and the implicit inherited operation).  This would solve the problem,
plus it fits in nicely with one possibility that Tucker suggested (if
I understood him correctly), that the explicit Operation should hide
the implicit one from all visibility, rather than overriding it.  I
don't know whether this particular change would cause more problems
than it solves; but I do think that simply legislating that the
explicit Operation should not be an overriding procedure is a fine
solution, since it seems consistent with how I think generics work.

On the other hand, if there's a belief that anyone who writes code
like the above has to be confused about how generics or tagged types
work, and that we should make it illegal since the user is probably
expecting something they're not going to get anyway, I'm not going to
object.  I don't see any particular use for the above sort of
construct anyway.

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

From: Randy Brukardt
Sent: Tuesday, March 23, 2004  6:51 PM

Adam wrote:

> OK, thanks for the explanation (and the one about the "primitive"
> error message).  While we're discussing "bad choice of language", I
> probably ought to point out that my original c.l.a post on the thread
> was an attempt to summarize very briefly what I had previously said on
> Ada-Comment, so there were probably important details left out.

In working on the minutes of the Phoenix ARG meeting, I discovered that we
approved AI-200 (an ancient AI that was previously tabled and since was
forgotten). It turns out to be on exactly this issue, even with similar
examples.

The AI goes into much discussion on these issues, and concludes to modify
3.2.3(7) to not apply to formal types. (So there is a language hole.)

I'm still concerned about Tucker's "hidden from all visibility" for the
original operations. I don't see how that follows from the language rules
(the language still describes them as "overriding", after all).

It's interesting that no one here remembered this AI, less than two weeks
after we voted to approve it. Which makes me wonder how well we understood
it when we approved it!

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


Questions? Ask the ACAA Technical Agent