!standard 12.6(10) 08-12-04 AI05-0131-1/01 !class binding interpretation 08-12-04 !status work item 08-12-04 !status received 08-10-23 !priority Low !difficulty Medium !qualifier Omission !subject Class-wide operations for formal subprograms revisited !summary ** TBD ** !question AI05-0071-1 allows an instantiation to automatically create a matching subprogram for a class-wide type if a primitive for the specific type is directly visible. However, this requires using a use clause to get the proper visibility, which can clutter the visibility with many unrelated subprograms. Moreover, the capability is not available if the subprogram is directly specified in the instantiation. It is very unusual in Ada to be able to do something by default that you cannot do explicitly. Should this be corrected? !recommendation (See Summary.) !wording ** TBD ** [I didn't try to figure out wording for this one. It would seem to be necessary to take the wording added to 12.6(10) by AI05-0071-1 and move it up to a separate paragraph preceding 12.6(10) so it would apply to all (non-abstract) formal subprograms - Editor] !discussion Consider an example like: package Pack1 is type Root is tagged record F1 : Integer; end record; procedure Oper_1 (X : in out Root); end Pack1; package Pack2 is generic type T(<>) is private; with procedure Oper_1 (X : in out T) is <>; package Gen_Pack is end Gen_Pack; end Pack2; with Pack1; with Pack2; package Pack3 is package Inst1 is new Pack2.Gen_Pack (Pack1.Root); -- ERROR: package Inst2 is new Pack2.Gen_Pack (Pack1.Root'Class); -- ERROR: package Inst3 is new Pack2.Gen_Pack (Pack1.Root, Pack1.Oper_1); -- OK package Inst4 is new Pack2.Gen_Pack (Pack1.Root'Class, Pack1.Oper_1); -- ERROR: use Pack1; package Inst5 is new Pack2.Gen_Pack (Pack1.Root); -- OK package Inst6 is new Pack2.Gen_Pack (Pack1.Root'Class); -- OK end Pack3; Inst1 is illegal because Oper_1 is not directly visible at the point of the instantiation. Inst2 is illegal for a similar reason. The use clause makes the similar Inst5 and Inst6 legal, the latter because of the new rules of AI05-0071-1. But if you want to explicitly give the subprogram (perhaps because the use clause drags in lots of other conflicting names), Inst3 is legal (of course), but Inst4 is not. Ada almost always allows using selected notation rather than use visibility (it even goes so far as to provide selection notation for operators!), but that is not the case here. That seems to be a mistake. --!corrigendum 12.6(10/2) !ACATS Test An ACATS C-test should test the revised rule. !appendix !topic Should AI05-0071 allow renaming subprograms? !reference AI05-0071 !from Adam Beneschan 08-10-23 !discussion The language of AI05-0071 allows for a generic to be instantiated with a class-wide type, and will allow the actuals for generic formal subprograms to be dispatching subprograms "created" by the compiler, in a sense. However, the language of AI05-0071 allows for this only if the operation is a primitive subprogram that is directly visible. I'm wondering whether this should be expanded a bit to allow renames. Consider this example, which doesn't involve instantiation with class-wide types: package Pack1 is type Root is tagged record F1 : Integer; end record; procedure Oper_1 (X : in out Root); end Pack1; package Pack2 is generic type T(<>) is private; with procedure Oper_1 (X : in out T) is <>; package Gen_Pack is end Gen_Pack; end Pack2; with Pack1; with Pack2; package Pack3 is package Inst is new Pack2.Gen_Pack (Pack1.Root); -- ERROR: end Pack3; This won't compile, because for the generic formal subprogram default to be used, Oper_1 would have to be visible. This can be accomplished with USE or USE TYPE. But another way, if it is undesirable to make everything directly visible that USE or USE TYPE would make visible, would be to use a rename: package Pack3 is procedure Oper_1 (X : in out Pack1.Root) renames Pack1.Oper_1; package Inst is new Pack2.Gen_Pack (Pack1.Root); end Pack3; This option doesn't appear to be available in the class-wide type case: package Pack3 is procedure Oper_1 (X : in out Pack1.Root) renames Pack1.Oper_1; package Inst is new Pack2.Gen_Pack (Pack1.Root'Class); end Pack3; The new language that AI05-0071 adds to 12.6(10) wouldn't apply because this subprogram rename isn't a primitive subprogram, and the subprogram that it renames, which is a primitive subprogram, is still not directly visible. It may not be the worst problem in the world, and you can work around it, but it's a little ugly: package Pack3 is package Dummy_Nested is use type Pack1.Root; package Inst is new Pack2.Gen_Pack (Pack1.Root'Class); end Dummy_Nested; package Inst renames Dummy_Nested.Inst; end Pack3; But should 12.6(10) as modified by this AI be modified to allow directly visible subprograms that are renames of primitive subprograms, as well as directly visible primitive subprograms? **************************************************************** From: Adam Beneschan Date: Thursday, October 23, 2008 12:34 PM > This won't compile, because for the generic formal subprogram default > to be used, Oper_1 would have to be visible. This can be accomplished > with USE or USE TYPE. Ummm, my bad. USE TYPE wouldn't work in the above case, but it would work if the subprogram were an operator. This actually makes the problem potentially a little worse than I thought, since it means that in the AI95-71 case, if the subprogram isn't an operator, you'd have to use USE instead of USE TYPE to make it directly visible, and there could be even more objection to that since it could make many other things directly visible. **************************************************************** From: Tucker Taft Date: Thursday, October 23, 2008 12:42 PM I don't see the need. This is a tricky enough implementation area as it is, so trying to wedge renames into this seems like overkill. By the way, a "use type" wouldn't help here because we aren't talking about an operator. **************************************************************** From: Randy Brukardt Date: Friday, October 24, 2008 7:39 PM Those of us from the society of use-adverse programmers would beg to differ. But I don't want renames, either, the problem in my mind is that the magic doesn't work for an explicit routine (only one that is defaulted). This is about the only case in Ada that I can think of where that is true. In Adam's example, I almost certainly would have given the parameter explicitly rather than insert a use clause: with Pack1; with Pack2; package Pack3 is package Inst is new Pack2.Gen_Pack (Pack1.Root, Pack1.Oper_1); end Pack3; which is a lot less work (and maintainance issues) than a renames! But the equivalent: with Pack1; with Pack2; package Pack4 is package Inst is new Pack2.Gen_Pack (Pack1.Root'Class, Pack1.Oper_1); -- ERROR: end Pack4; is illegal, because Oper_1 doesn't match. The only choices are to put in a full use clause (no way) or to define your own Oper_1 (note that I don't see any value to a rename here, either, the full routine isn't much longer): with Pack1; with Pack2; package Pack4 is procedure Oper_1 (X : in out Pack1.Root'Class); package Inst is new Pack2.Gen_Pack (Pack1.Root'Class, Oper_1); end Pack4; package body Pack4 is procedure Oper_1 (X : in out Pack1.Root'Class) is begin Pack1.Oper_1 (X); end Oper_1; end Pack4; Obviously, this extra routine adds additional junk to maintain and an additional source of errors. And it's weird that an implicit subprogram can be built if no name is given here, but giving an explicit name loses this option. **************************************************************** From: Tucker Taft Date: Friday, October 24, 2008 9:00 PM I would be more sympathetic to making the explicit parameter work than making the rename work. I would think the adjustment to the wording to make the explicit parameter work might not be too horrendous. ****************************************************************