[net.lang.c++] Overloading

bs@alice.UucP (Bjarne Stroustrup) (03/17/86)

> From: dmiruke@isis.UUCP (Dataram Miruke)
> Subject: Re: Function Overloading
> Organization: University of Denver Math and Computer Science
> 
> See page 290-291, in "The C++ Programming Language". In particular bs says ...
> 
> 	" When that name is used (overloaded name), the correct function is
> selected by comparing the types of the actual arguments with the formal
> argument types.
> 	Finding which function to call is done in three steps :
>  1. Look for an exact match and use it if found.
>  2. Look for a match using the standard conventions and use any one if found.
>  3. Look for a match using user-defined conversions. If a unique set of
>     conversions is found then use it.
>     ....... "
> 
 >    -- though the term "any one" in (2) above bothers me a bit. what if there
> are more than one matches? how does the selection proceeds then? Maybe bs could
> make it a bit clearer.

As the book says in case 2 the compiler picks ``any one''. It also gives a
warning so that you can disambiguate the call yourself. The ``classic''
example is this:

	overload print;
	void print(long), print(double);
	print(1);

The integer 1 can be promoted to either long or double and there does not
appear to be any fundamental reason to prefer one over the other. In real
examples there is no way of guessing the programmer's intention. We
could have a rule, but it would be arbitrary, and in about 50% of the
cases ``wrong''. Instread you get a warning:

"", line 4: warning: more than one standard conversion possible for print()

The standard fix is to provide a function to disambiguate all such calls:
	inline void print(int i) { print( long(i); }


> 	I believe that since the compiler uses the fact that the proper
> selection amongst the overloaded functions is done with the help of argument
> types it is important for the compiler to be able to differentiate between the 
> arguments at least to some extent. May be in the new version of c++ bs should
> also consider the return type of the functions.

I'd rather not. I looked at that and found it a can of worms. Have a look at Ada.

> PS : (To bs specifically) : Have you considered adding the facility to let the
> programmer define the new operators, rather than restricting him/er to use the
> existing operators.

I have, see pg 171. Basically, the ``restriction'' is there because I believe
that removing it is not worth the effort. You get less than what you'd
expect from that at a higher cost than you'd expect.

For a general mechanism you must be able to
	(1) define a new lexical token
	(2) specify it to be unary (prefix or postfix) or binary,
	(3) specify its precedence and binding (left or right)
This can be done (see Algol68) but involves extra language constructs
and either a dynamically programmable lexical scanner or a two pass compiler.
It also opens the next question: ``if I can define new operators, why not new
statements''. That too has been tried: Just add a LR parser generator to the
language. I decided to keep C++ somewhat simple. After all, I had to implement
it, write the manual, and suffer from the mistakes.

You can also look at it from another angle: Why not just provide a few useful
``extra'' operators? (SETL did that - in the first version only). So I asked
around. People wanted operators ** // <- -> etc. The first three can only be
provided by breaking existing programs, and the first (and by far most popular)
gives rise to religious wars over which way it binds: Does a**b**c mean
(a**b)**c or a**(b**c)?

	- Bjarne Stroustrup (AT&T Bell Labs, Murray Hill)

nathan@orstcs.UUCP (nathan) (03/20/86)

>You can also look at it from another angle: Why not just provide a few useful
>``extra'' operators? (SETL did that - in the first version only). So I asked
>around. People wanted operators ** // <- -> etc. ...
>
>	- Bjarne Stroustrup (AT&T Bell Labs, Murray Hill)

This brings up a discussion which should *not* be carried on further
in this group: everybody's favorite unimplemented operators.

Just to break my own rule, I propose
	spp->>f == (*spp)->f  == (**spp).f
for dereferencing "handles".  Perhaps a better solution would be to define
a right-binding dereference operator, "^", so that we could say
	s.f ==  sp^.f == spp^^.f
and not need any funny precedence-hacks.  Isn't originality wonderful? :-)

BTW, I'm curious why the "." and "->" operators aren't real operators.
Obviously there isn't any standard type for their right operand, but
is the answer more subtle than this?

Nathan C. Myers		orstcs!nathan		nathan@oregon-state

kwh@bentley.UUCP (KW Heuer) (03/25/86)

In article <34200008@orstcs.UUCP> orstcs!nathan (nathan) writes:
>Just to break my own rule, I propose
>	spp->>f == (*spp)->f  == (**spp).f
>for dereferencing "handles".  Perhaps a better solution would be to define
>a right-binding dereference operator, "^", so that we could say
>	s.f ==  sp^.f == spp^^.f
>and not need any funny precedence-hacks.  Isn't originality wonderful? :-)

Actually, there *is* a right-binding dereference operator: "[0]".
(Yes, I know it's not perfect -- it won't apply to function pointers, e.g.)
(Btw, "^" is a bad choice; it changes the meaning of "x ^ - y".)

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint