!standard 03.02.03 (07) 98-03-27 AI95-00200/00 !class binding interpretation 98-03-27 !status received 98-03-27 !priority Low !difficulty Medium !subject Generic formal subprograms as dispatching operations !summary 98-03-27 !question 98-03-27 !recommendation 98-03-27 !wording 98-03-27 !discussion 98-03-27 !appendix 98-03-27 !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 ****************************************************************