!standard 12.3 06-11-13 AC95-00137/01 !class Amendment 06-11-13 !status received no action 06-11-13 !status received 06-11-03 !subject Specifying overloaded routines in a generic instance !summary !appendix [Editor's note: This appeared as an aside in an unrelated discussion; only the mail on the aside is filed here. The rest is filed in AI05-0025-1.TXT.] From: Adam Beneschan Date: Friday, November 3, 2006 6:00 PM (P.S. I'll reiterate something I said on comp.lang.ada: it might be helpful to have a way in such cases to allow programmers to use the <> syntax of formal subprograms but allow the name to be different from the name of the formal subprogram, something like this:) generic type T1 is private; type T2 is private; with function T1_Equal (Left, Right : T1) return Boolean is <> ("="); with function T2_Equal (Left, Right : T2) return Boolean is <> ("="); package GP1 is ... **************************************************************** From: Randy Brukardt Date: Friday, November 3, 2006 10:21 PM But this solves the wrong problem; we really want the names of the functions inside the generic to be overloaded and "=". I don't want to have to write "if T1_Equal (A, B) then" because that requires figuring out the type name (often the thing I find hardest to remember; usually I know the objects, but not [exactly] the types). Moreover, the above could cause subtle bugs: if I write "if A = B then" I'll get the original "=", not the one passed in. Which will work fine until someone tries to use a custom "=". Yuck. The problem here is that we don't handle overloading of parameter names, so what we need is a way to rename the parameter names for the formals. One option would be something like: generic type T1 is private; type T2 is private; with function "=" (Left, Right : T1) return Boolean is <> named T1_Equal; with function "=" (Left, Right : T2) return Boolean is <> named T2_Equal; package GP1 is ... and in this case, you'd be required to use the name in the "named" clause as the parameter name in instantiations and formal packages. That is, your example above would become: with package The_Pak1 is new GP1 (T1 => T1, T2 => T2, T1_Equal => <>, T2_Equal => <>); which is not a problem. Use of "=" => <> would be illegal, even if not overloaded. (Of course, in this particular example, it probably would have been better to say: with package The_Pak1 is new GP1 (T1 => T1, T2 => T2, others => <>); which requires no new language, but that doesn't hold for instantiations.) Still, this seems to be a minor problem. **************************************************************** From: Adam Beneschan Date: Monday, November 6, 2006 10:21 AM > But this solves the wrong problem; we really want the names of the functions > inside the generic to be overloaded and "=". I figured you could use a rename inside the generic declaration to get around that: function "=" (Left, Right : T1) return Boolean renames T1_Equal; Maybe it won't work for some reason that I haven't thought of. But doing it the other way, as per your suggestion > generic > type T1 is private; > type T2 is private; > with function "=" (Left, Right : T1) return Boolean > is <> named T1_Equal; > with function "=" (Left, Right : T2) return Boolean > is <> named T2_Equal; > package GP1 is ... would be OK also. The biggest problem I can think of there is that if you want to use named association in an instantiation, and you're looking at the generic declaration to figure out what the names of the formals are, this may make it a bit harder since the name would be in an unusual place (i.e. this would be the only case where the name is not the first non-keyword in a generic_formal_parameter_declaration). But perhaps that's a minor point. I agree that the issue is probably a minor one anyway, although it did come up based on an actual example that someone on c.l.a was trying to write. **************************************************************** From: Robert A. Duff Date: Monday, November 6, 2006 2:44 PM >... I agree that the issue is probably > a minor one anyway, although it did come up based on an actual example > that someone on c.l.a was trying to write. I've run into this issue myself. But I think it's not sufficiently broken to be worth fixing. **************************************************************** From: Tucker Taft Date: Monday, November 6, 2006 5:19 PM I would rather directly solve the problem of being unable to use named notation when there is overloading. We could adopt a syntax analogous to that used for referring to different dimensions of an array, e.g: "="(1) => Foobar, "="(2) => Fum Not pretty, but it seems pretty clear what it means. **************************************************************** From: Pascal Leroy Date: Tuesday, November 7, 2006 3:04 AM Well, this is hardly better than positional notation, in the sense that if the order of the formal parameters changes in the generic surprising things can happen. I am not really annoyed by the fact that you cannot give named associations for overloaded formal subprograms. What I find obnoxious is that, because formal subprograms tend to occur late in the list of formal parameters, this forces many other parameters to use positional notation, even though they don't involve overloading. We could alleviate this problem without inventing weird new syntax by simply relaxing a bit the positional-before-named rule in this case. **************************************************************** From: Robert A. Duff Date: Tuesday, November 7, 2006 5:18 PM >...We could alleviate this > problem without inventing weird new syntax by simply relaxing a bit the > positional-before-named rule in this case. The "positional-before-named rule" was a bad idea from the start. But how can we relax it now, without compatibility concerns? **************************************************************** From: Simon Wright Date: Tuesday, November 7, 2006 5:34 PM Would using generic signature packages have got round the original problem? **************************************************************** From: Randy Brukardt Date: Tuesday, November 7, 2006 6:00 PM Not sure which problem you are referring to. The original bug that Adam reported is in the definition of generic formal packages. Splitting the package into two would eliminate the concern, but that's irrelevant, since the rules would still be wrong and need fixing. The off-topic aside has an example with two "=" operators. I suppose spliting that formal package into two would work in that case, but it's not a general solution, and it would add complexity (using two formal packages instead of one). (To see why it is not general, imagine a package with multiple mixed "+" operators, or multiple Put routines, or any other overloading on a single type.) The generalization of the off-topic aside might benefit from using a formal package instead, but again you are adding complexity. I don't think a signature package is a good solution when all you are talking about are predefined operators; it makes more sense with a more complex set of operations. (And one wonders whether an interface isn't a better solution then, but I digress.) So I think the answer is no - it might help in some specific example, but is not general in any way. **************************************************************** From: Adam Beneschan Date: Tuesday, November 7, 2006 6:03 PM > Would using generic signature packages have got round the original > problem? I assume that by "original problem" you mean the second one I briefly alluded to my first message---not the missing rule that's the subject of the thread. (The "missing rule" problem isn't something that needs to be gotten around.) The situation was something like this: generic type T1 is private; type T2 is private; with function "=" (Left, Right : T1) return Boolean is <>; with function "=" (Left, Right : T2) return Boolean is <>; package GP1 is ... end GP1; The main problem, as I see it: If, when instantiating, you want to use something other than the default for one or both of the "=" subprograms, then you can't use named notation when you instantiate (even for the T1 and T2 formals)---you have to use positional notation. And Ada doesn't give you a way to allow named notation by naming the formal "=" subprograms something else. But you can still do the instantiation; I don't think this problem causes a situation where you can't do something you need to do. You can do what you need, you just can't do it in the most readable way. (And you can add comment(s) near the instantiation to help explain things, if needed.) That's probably why Randy referred to this as a minor problem. Generic signatures thus aren't needed to get around any problem, and I don't think they'd enhance readability at all. IMHO they'd just add needless clutter. **************************************************************** From: Pascal Leroy Date: Wednesday, November 8, 2006 2:39 AM > The "positional-before-named rule" was a bad idea from the > start. But how can we relax it now, without compatibility concerns? If we were to relax this rule (and I am only talking about generic instantiations with overloaded formal parameters) then you could write something like: T => Integer, C => 42, "+", "+" and this would not create any incompatibility because such an ordering is currently always illegal. Of course, the rules would have to be crafted carefully so that we do not lose coverage checking and all these good things. **************************************************************** From: Adam Beneschan Date: Wednesday, November 8, 2006 12:10 PM > I am not really annoyed by the fact that you cannot give named > associations for overloaded formal subprograms. What I find obnoxious is > that, because formal subprograms tend to occur late in the list of formal > parameters, this forces many other parameters to use positional notation, > even though they don't involve overloading. We could alleviate this > problem without inventing weird new syntax by simply relaxing a bit the > positional-before-named rule in this case. Another possibility would be to keep the positional-before-named rule, but relax 12.3(9) to allow named associations where multiple formal subprograms have the same name. The first such named association in the instantiation would be for the first formal with that name, the second (if any) would apply to the second formal with that name, etc. I'd want a rule that you could not use both a positional association and a named association in the same instantiation to apply to formal subprograms with the same name, to avoid some really confusing possibilities. Like Pascal's suggestion, this has the advantage of not requiring any new syntax. A disadvantage of both approaches is that if you have two "=" formal subprograms, you can't let the first one default and specify an actual parameter for the second, although it's easy to enough to write "=" => "=" for the first so this probably isn't a big disadvantage. **************************************************************** From: Tucker Taft Date: Wednesday, November 8, 2006 12:21 PM I think I marginally prefer Adam's suggestion, namely that you can give the same name twice if the generic formal is overloaded. I would go further and require that if you use a named parameter for an overloaded name, then you must give one for *each* overloading of the name, to make it crystal clear that you are aware that the name is overloaded, and you are specifying what you want for each one. Yes this defeats using defaults, but the potential for error seems just too high if you are allowed to specify just one of two overloaded parameters, since you might just not have noticed that there was an earlier parameter with the same name. **************************************************************** From: Robert A. Duff Date: Wednesday, November 8, 2006 3:03 PM I agree with all of the above, assuming we really want to fix this problem at all. I still say, "insufficiently broken". By the way, here's a workaround: declare two generic packages. One uses names like This_Equal and That_Equal. The other uses "=" and "is <>". One instantiates the other. If you want to use named notation, instaniate the former. If you want to take advantage of "is <>", instantiate the latter. **************************************************************** From: Jean-Pierre Rosen Date: Thursday, November 9, 2006 12:56 AM > Like Pascal's suggestion, this has the advantage of not requiring any > new syntax. A disadvantage of both approaches is that if you have two > "=" formal subprograms, you can't let the first one default and > specify an actual parameter for the second, although it's easy to > enough to write "=" => "=" for the first so this probably isn't a big > disadvantage. I agree with that, but you need to allow "=" => <> for defaulted value. The default may not be visible at the place of the instantiation, so you really need a way to specify that you want the default. **************************************************************** From: Adam Beneschan Date: Thursday, November 9, 2006 10:17 AM Maybe. But the whole idea was that the problem only occurs when the *generic* *formal* is specified with a <> default: generic type T1 is private; type T2 is private; function "=" (Left, Right : T1) return Boolean is <>; function "=" (Left, Right : T2) return Boolean is <>; package ... and if I understand the rules correctly, "=" => "=" is always equivalent to not specifying an explicit actual (12.6(10)). This case is a problem because the Ada syntax doesn't give you a way to specify the generic formal subprograms with unique names. In the case I think you're thinking of, where the *generic* *formal* has an explicit default: generic ... with procedure Output (X : String) is Text_IO.Put_Line; there's no issue because you can always give the generic formal subprograms unique names. I suppose it could become an issue if someone really, really, really wants to overload a generic formal subprogram name when they don't need to: generic ... with procedure Output (X : String) is Text_IO.Put; with procedure Output (X : Character) is Text_IO.Put; but I don't see why anybody would want to. Still, since Ada 200Y allows => <> in aggregates, it wouldn't be too much of a stretch to allow it in instantiations also, although I don't think it's necessary. **************************************************************** From: Christoph Grein Date: Wednesday, November 8, 2006 2:15 AM > The "positional-before-named rule" was a bad idea from the start. I disagree. How should an expression like F(A, P => Q, B, X => Y) be interpreted? We would have to add still new rules with questionable use. > But how can we relax it now, without compatibility concerns? I also see the problem with generics and once suffered from it. But: Is this inconvenience really worth a language change? **************************************************************** From: Robert A. Duff Date: Wednesday, November 8, 2006 3:21 PM > I disagree. How should an expression like F(A, P => Q, B, X => Y) be > interpreted? We would have to add still new rules with questionable use. Not new rules -- different rules. If I ran the circus, overload resolution would ignore the parameter names. The above would be resolved as for F(A, Q, B, Y). Then, after overload resolution, a legality rule would require that the name of the second parameter be P, and the fourth X. Defaulted parameters should be equivalent to expanding out all the overloaded versions without defaults. Thus: procedure P (X : T1 := 1; Y : T2; Z : T3 := 3); would be equivalent to: procedure P (X : T1; Y : T2; Z : T3); procedure P (X : T1; Y : T2); procedure P (Y : T2; Z : T3); procedure P (Y : T2); This would make it useful to have defaulted parameters before non-defaulted ones. For example, consider Text_IO.Put_Line. Conceptually, we want it to take two arguments, a file and a string, with the file defaulting to "standard output". You can't do that in Ada, which means you have to have two Put_Line's, which is a kludge. As I said, this would be incompatible, and therefore out of the question for Ada. > > But how can we relax it now, without compatibility concerns? > > I also see the problem with generics and once suffered from it. But: Is > this inconvenience really worth a language change? No. **************************************************************** From: Jeffrey Carter Date: Wednesday, November 8, 2006 5:59 PM > This would make it useful to have defaulted parameters before non-defaulted > ones. For example, consider Text_IO.Put_Line. Conceptually, we want it to > take two arguments, a file and a string, with the file defaulting to "standard > output". You can't do that in Ada, which means you have to have two > Put_Line's, which is a kludge. Actually, it defaults to Current_Output, which defaults to Standard_Output. The only problem here is the insistence that the file parameter has to come 1st. There's no reason it couldn't have been procedure Put_Line (Item : in String; File : in File_Handle := Current_Output); You could still write calls identical to what is done now: Put_Line (Item => "Hello"); Put_Line (File => Fred, Item => "World"); **************************************************************** From: Robert A. Duff Date: Wednesday, November 8, 2006 7:19 PM > > This would make it useful to have defaulted parameters before non-defaulted > > ones. For example, consider Text_IO.Put_Line. Conceptually, we want it to > > take two arguments, a file and a string, with the file defaulting to "standard > > output". You can't do that in Ada, which means you have to have two > > Put_Line's, which is a kludge. > > Actually, it defaults to Current_Output, which defaults to Standard_Output. Ah, yes, I had forgotten about the Current_Output silliness. ;-) > The only problem here is the insistence that the file parameter has to come > 1st. There's no reason it couldn't have been > > procedure Put_Line > (Item : in String; File : in File_Handle := Current_Output); I find it very natural that the File come first. Maybe it's just what I'm used to. > You could still write calls identical to what is done now: > > Put_Line (Item => "Hello"); > Put_Line (File => Fred, Item => "World"); I want to write: Put_Line(Out_File, "Hello"); Named notation is for readability. A vague name like "Item" doesn't add readability; it should be left out at the call site. And named notation is NOT for people who are too lazy to look up the declared order. If I ran the circus, the order of actuals would be required to be the same as that of the formals. I would certainly find it confusing to declare Put_Line with the File second, and then call it with the File first. **************************************************************** From: Jeffrey Carter Date: Wednesday, November 8, 2006 10:43 PM > I find it very natural that the File come first. Maybe it's just what > I'm used to. The C library (fgets, fputc, fputs) has the file last. Coming from Pascal, though, I was used to it 1st, too. > Named notation is for readability. A vague name like "Item" doesn't add > readability; it should be left out at the call site. And named notation is NOT > for people who are too lazy to look up the declared order. If I ran the > circus, the order of actuals would be required to be the same as that of the > formals. And when I'm king, procedure calls will have to use named notation, so there will some additional pressure to use meaningful parameter names. **************************************************************** From: Pascal Leroy Date: Thursday, November 9, 2006 2:04 AM > And named notation is NOT for people who are too lazy > to look up the declared order. If I ran the circus, the > order of actuals would be required to be the same as that of > the formals. This is turning into a discussion of the Duff language, not of Ada, so maybe it should be posted on Duff-Comment ;-) Named notation is for maintenance. Occasionally, I find myself changing the order of parameters during maintenance, not because of some rule of the language, but because I discover that the parameters are not in their "natural" order. Since I used named notation pretty systematically, the existing call sites don't have to be modified. OK, they may not be ideal, but I am not going to edit them all. (I work on a fairly large project.) New calls can be written using the preferable order, and over time existing calls may be changed, too. When this situation arises, I am happy that I use Ada and not the Duff language... **************************************************************** From: Jeff Cousins Date: Monday, November 13, 2006 9:43 AM > The C library (fgets, fputc, fputs) has the file last. Coming from Pascal, though, I > was used to it 1st, too. The C library's fprintf has the file first, so C isn't consistent. ****************************************************************