Version 1.3 of acs/ac-00137.txt

Unformatted version of acs/ac-00137.txt version 1.3
Other versions for file acs/ac-00137.txt

!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.

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


Questions? Ask the ACAA Technical Agent