Why can't overloads take into account the return type.

S

Steve Walker

Michael C said:
Overloading makes the language harder to learn, as does inheritance and
interfaces, we'd better leave those out too. :)

It's a trade-off of utility against complexity. I'd be on the "not worth
it" side of the debate. I can't see that it would be a useful enough
feature to be worthwhile, and I think that if C# had it, and I found
myself using it, I'd immediately suspect that I needed to refactor the
code.

If the different versions of the method were semantically identical, you
would just be hiding a cast or conversion. Assuming simple types, I can
only see that you might want to encapsulate that if it were doing
something specific to the context of the class. If that were the case
you could create non-intuitive anomalies; if int Foo(){} and float
Foo(){} were overloads with different return types, and int Foo(){} did
something other than cast a float to an int, you may end up with

(int)Foo() != (int)(float)Foo()

If the methods returned instances of classes of my own making, I'd look
at returning a supertype.

If they were not semantically identical, they should have had different
names.
 
D

Daniel O'Connell [C# MVP]

Michael C said:
The compiler is going to need to know the return type anyway. I don't see
it much different from:

Parse(Something, ref x);

Why would you see it as that? The two are semantically different.

Anyway, yes the compiler already knows the return type, but it is capable fo
determing the return type from the method call alone. To overload on return
type would require more information than the method call alone can provide.
Overloading makes the language harder to learn, as does inheritance and
interfaces, we'd better leave those out too. :)

You realize, everyone uses this argument for everything. This is as
effective of a reason for insisting that the language must require case to
change for every letter of an identifier as it is for this.

As Steve Walker points out, its utility verse complexity. Inheritance and
interfaces offer significant utility with moderate complexity whereas return
type overloading provides minimal utliity with significant complexity.

But it can do it and it makes sense to the programmer for it to be double
all the way through.

It does? To me it doesn't in *ANY* way tell me that Parse() should be
returnign a double without knowing that the specific Calc method is tied to
the type of the return type. I don't think that is clear in any way. That is
like saying that I can tell from a baby what its grandfather looks like.
Sure, its possible, but its a shot in the dark unless you already know the
answer.

And,then, what does something like

this.Property = Calc(Parse(GetString()))

mean? The type is hidden and all three method calls are terribly ambigious
from the programmers point of view.

Let me ask you this, have you *ever* used an OO langauge that allows return
type overloading, especially one that determines the method to call
automatically?
I'm sure it can get complex but in any case it can't resolve the call it
should just say so. Programmers would know to specify the return type in
the necessary cases. Maybe something like double d =
Calc((double)Parse("15")): could be used.

Yet that is ambigious at best, what do you do when you end up needing code
you can't write because the compiler cannot resolve what you are doing?

And, more importantly, *WHY* is all this better than just DoubleFromString()
and IntFromSTring() ?
 
M

Michael C

Steve Walker said:
It's a trade-off of utility against complexity. I'd be on the "not worth
it" side of the debate. I can't see that it would be a useful enough
feature to be worthwhile, and I think that if C# had it, and I found
myself using it, I'd immediately suspect that I needed to refactor the
code.

It could be made a lot simpler by giving an error if the return type was not
completely obvious. eg Parse(Calc("1.0")) could give an error unless it was
specified as Parse((int)Calc("1.0")) or int x = Calc("1.0").
If the different versions of the method were semantically identical, you
would just be hiding a cast or conversion. Assuming simple types, I can
only see that you might want to encapsulate that if it were doing
something specific to the context of the class. If that were the case you
could create non-intuitive anomalies; if int Foo(){} and float Foo(){}
were overloads with different return types, and int Foo(){} did something
other than cast a float to an int, you may end up with

(int)Foo() != (int)(float)Foo()

Same problem can potentially apply with current overloads though so I don't
see it as a problem.
 
M

Michael C

Daniel O'Connell said:
Why would you see it as that? The two are semantically different.

There is a difference but there is also a similarity. Did you fail to see
it?
Anyway, yes the compiler already knows the return type, but it is capable
fo determing the return type from the method call alone. To overload on
return type would require more information than the method call alone can
provide.

It would still be able to achieve it.
You realize, everyone uses this argument for everything. This is as
effective of a reason for insisting that the language must require case to
change for every letter of an identifier as it is for this.

As Steve Walker points out, its utility verse complexity. Inheritance and
interfaces offer significant utility with moderate complexity whereas
return type overloading provides minimal utliity with significant
complexity.

In the end it is a matter of opinion though if the complexity outweighs the
gain.
It does? To me it doesn't in *ANY* way tell me that Parse() should be
returnign a double without knowing that the specific Calc method is tied
to the type of the return type. I don't think that is clear in any way.
That is like saying that I can tell from a baby what its grandfather looks
like. Sure, its possible, but its a shot in the dark unless you already
know the answer.

And,then, what does something like

this.Property = Calc(Parse(GetString()))

mean? The type is hidden and all three method calls are terribly ambigious
from the programmers point of view.

It probably is but *you* wrote the ambiguous code. If you think it's a
problem then don't write ambiguous code.
Let me ask you this, have you *ever* used an OO langauge that allows
return type overloading, especially one that determines the method to call
automatically?

Of course not.
Yet that is ambigious at best,

No more ambiguous as current overloads.
what do you do when you end up needing code you can't write because the
compiler cannot resolve what you are doing?

I don't see how that could possible happen.
And, more importantly, *WHY* is all this better than just
DoubleFromString() and IntFromSTring() ?

For the same reason current overloads are better.

Michael
 
D

Daniel O'Connell [C# MVP]

For the same reason current overloads are better.

Current overloads have visible, obvious differences though

Method(a)
Method(a,b)

obviously two different methods

Method(a)
Method(a)

thats not obvious. If you consider it better only in theory, I'll agree with
you, but I do not htink it offers *ANY* value within a language such as C#.
I suspect it'd hurt alot more than it'd help.

I'm going to end this discussion here as it has degenerated to "it can be
done so why isn't it". It isn't because its a bad idea and will turn your
code into a nightmare, if you can't see that or dont share the opinion,
fine, just accept that I think return type overloading with automatic return
type determination one of the worst possible features one could add to a
language.
 
J

Jon Skeet [C# MVP]

Michael C said:
Of course not.

Out of interest, why do you think that is? You're not the first person
to come up with this idea, so if it's such a good idea, why do you
think it hasn't made it into any languages?

While I can see it would allow us to get away from having lots of
methods with different names but the same parameter types, that's the
*only* advantage I can see, and that situation comes up pretty rarely
in my experience. I don't think it justitifies making the language
significantly more complicated.
 
M

Michael C

Daniel O'Connell said:
Current overloads have visible, obvious differences though

Method(a)
Method(a,b)

obviously two different methods

Method(a)
Method(a)

thats not obvious.

Of course it's not obvious, you haven't written the entire signature ffs!!!
*You* have left off the part that is different!!! I could use the same
stupid arguement against the current overloads. What's the difference
between

Method
Method

gee, we better not have overloads :)
If you consider it better only in theory, I'll agree with you, but I do
not htink it offers *ANY* value within a language such as C#. I suspect
it'd hurt alot more than it'd help.

It offers the same value current overload offer, reducing the number of
names for a function. If you think there is no value you are not thinking
straight.
I'm going to end this discussion here as it has degenerated to "it can be
done so why isn't it". It isn't because its a bad idea and will turn your
code into a nightmare,

It could potentially turn stupid people's code into a nightmare but likewise
any other feature.
if you can't see that or dont share the opinion, fine, just accept that I
think return type overloading with automatic return type determination one
of the worst possible features one could add to a language.

I accept that is your opinion.

Michael
 
W

Willy Denoyette [MVP]

Michael C said:
I'd bet my house I'm right. The only exception is modules but anything in
a class, form or usercontrol works as I described even if the class is
private.

Michael

Mind to prove your claim? That is prove that VB6 uses COM interfaces when
accessing regular VB6 Classes/Methods, note I'm NOT talking about accessing
VB6 authored Com/ActiveX classes (usercontrol) or toolbox classes (like
Forms, Listboxes etc...) from VB6 clients, just plain simple VB6 Classes.

Willy.
 
S

Steve Walker

Michael C said:
It could be made a lot simpler by giving an error if the return type was not
completely obvious. eg Parse(Calc("1.0")) could give an error unless it was
specified as Parse((int)Calc("1.0")) or int x = Calc("1.0").

My concern is more that if I found myself using it, I'd wonder whether
my design was flawed. I can see a small set of cases where it would be
harmless; for instance I have a class which wraps a DataRow and has
methods like:

public int GetInt(string name)
public DateTime GetDateTime(string name)
public string GetString(string name)
public bool GetBool(string name)

etc.

The sole purpose of that class is to handle DBNull values in a
particular way, and the methods are mutually exclusive for any given
type; if the underlying database data type isn't what you think it is,
you'll get an exception.

I think that in anything other than a simple utility class, overloaded
return types would be a code smell, and I'd want to look at why the
method name was so ambiguous. If it's reasonable to overload return
types, it's probably more reasonable to have a single method returning a
superclass of the overloaded types. If there isn't a sensible superclass
for the overloaded types, the overloads are returning totally different
things, and should probably be different methods.
Same problem can potentially apply with current overloads though so I don't
see it as a problem.

What, in terms of overloading operators to define casts? In that
situation, you're doing something subtly different; what you are
achieving as a user of the code is more transparent. They are also
something I'd use with care. I wouldn't want to represent the
calculation of a scalar quantity from a vector quantity with a cast, for
example.
 
M

Michael C

Willy Denoyette said:
Mind to prove your claim? That is prove that VB6 uses COM interfaces when
accessing regular VB6 Classes/Methods, note I'm NOT talking about
accessing VB6 authored Com/ActiveX classes (usercontrol) or toolbox
classes (like Forms, Listboxes etc...) from VB6 clients, just plain simple
VB6 Classes.

No problem, although I didn't say it uses COM interfaces for everything, I
said that it puts the return type as the last parameter and the actual
return value is the error information. There may be other complexities of
COM that it doesn't implement underneath.

The reason I know it does this is because I was once mucking around with
getting API callbacks to go directly into classes in vb4. I created some
assembly code in a byte array that would fix up the stack and call the
function in the class. I noticed that it didn't matter if the function with
public, private or friend or if the class was public or private I was still
able to find it in the VTable and call it in exactly the same way. The only
difference was that private functions appeared after the public ones. In all
cases a function like this:

Public Function AddOne(ByVal SomeParam as Long) as Long

would actually be something like (I'm not sure of the correct syntax)

Public Function AddOne(ByVal This as Long, ByVal SomeParam As Long, ByRef
RetVal as Long) as HRESULT

Michael
 
M

Michael C

Jon Skeet said:
Out of interest, why do you think that is? You're not the first person
to come up with this idea, so if it's such a good idea, why do you
think it hasn't made it into any languages?

For some reason language writers seem to like to keep things consistant with
previous languages.
While I can see it would allow us to get away from having lots of
methods with different names but the same parameter types, that's the
*only* advantage I can see,

That's the only advantage of the current overloads.
and that situation comes up pretty rarely
in my experience. I don't think it justitifies making the language
significantly more complicated.

I don't see it as much greater complexity. For example if they'd
implemeneted it for the datareader you might have to write it as
(int)reader.Value(1) instead of reader.GetInt(1). If the compiler complained
in any situation that was not dead obvious then it could work quite well.

Michael
 
J

Jon Skeet [C# MVP]

Michael C said:
For some reason language writers seem to like to keep things consistant with
previous languages.

Given how many experimental languages there are, that seems unlikely to
me. There are plenty of languages which try lots of different things,
and the best concepts usually work their way into the mainstream
eventually. I think there's a good reason for overloading by return
type not making it - it adds too much complexity for too little
benefit.
That's the only advantage of the current overloads.

The difference is how often that's useful compared with how often
overloading by return type would be useful though. Look at all the
examples of overloading by parameters in the framework, and then think
of how many places overloading by return type would really be useful.
Places I can think of:

DataReader
Convert
BitConverter
Stream
TextReader
BinaryReader
Marshal

Frankly, in all those places I think having the instantly readable an
unambiguous calls is often more of a blessing than a curse. Arguably
having more explicit alternatives to overloading for writing in some of
the above would be a better way to improve things - and at no language
complexity cost.
I don't see it as much greater complexity. For example if they'd
implemeneted it for the datareader you might have to write it as
(int)reader.Value(1) instead of reader.GetInt(1). If the compiler complained
in any situation that was not dead obvious then it could work quite well.

It's a fundamentally more complicated language though, as the type of
an expression would depend on its context in a way in which it simply
doesn't now.
 
H

Helge Jensen

Overloading on the return type means that you cannot determine the type
of an expression without looking at it's context.

That is undesireable because it prevents using compositional recursion
to evaluate the type of the expressions of the program.

As a small taste of the problem, given definitions:

X f(Y);
Y f(X);
X x; Y y;

Which error would you give on:

y = f(f(x))

Hint: there are two possible errors:

1: cannot covent argument 1 of "X f(Y)" from type X to type Y
2: cannot assign type X to type Y

Depending on whether you overload by the arguments or the return-type.

Besides, if you wish to overload on the "return-type", just use:

f(out X x, Y y);
f(out Y y, X x);

I suggest trying to write a staticly typed compiler to get to really
understand this problem.
 
M

Mike Schilling

Helge Jensen said:
Overloading on the return type means that you cannot determine the type of
an expression without looking at it's context.

That is undesireable because it prevents using compositional recursion to
evaluate the type of the expressions of the program.

As a small taste of the problem, given definitions:

X f(Y);
Y f(X);
X x; Y y;

Which error would you give on:

y = f(f(x))

Hint: there are two possible errors:

1: cannot covent argument 1 of "X f(Y)" from type X to type Y
2: cannot assign type X to type Y

Or 3: f(x) is ambiguous.

Overloading on return type is (IMHO) a bad idea, and allowing it in
situations where the return type isn't completely unambiguous is fatal.
Even
y = f((Y)f(x));

is problematical: what if there's a conversion from X to Y?
 
S

stork

This is about control over types.

Right now we as developers want to hold all the cards on type control,
and I'm wondering if that complexity is really worth it.

Consider the example:

y = f((Y)f(X));

to evaluate the type for this, start with the type of y.

Then, select the f() whose return type matches y.

For the inside call, you force, by cast, the selection of an f(X) that
returns a Y.

At this point, you can have an error. There may not be an f() that
satisfies the type requirements that we established. Compilation
halts.
 
M

Michael C

Helge Jensen said:
Which error would you give on:

y = f(f(x))

Very simple. You give an error that states it is ambiguos, forcing the
programmer to specify the return type they wish to use. I don't see this as
that difficult.
I suggest trying to write a staticly typed compiler to get to really
understand this problem.

Irrelevant, it is achievable by ms.

Michael
 
M

Michael C

Helge Jensen said:
Which error would you give on:

y = f(f(x))

This is going around in circles. Everyone keeps saying it would be overly
ambiguous. I respond by saying that ambiguity can be got around by forcing
the programmer to specify the return type in any case where there is more
than one option, eg (int)Parse("1"). Everyone keeps repeating that it will
be too ambiguous without responding to my point. Must be a good point :)

Michael
 
J

Jon Skeet [C# MVP]

Michael C said:
This is going around in circles. Everyone keeps saying it would be overly
ambiguous. I respond by saying that ambiguity can be got around by forcing
the programmer to specify the return type in any case where there is more
than one option, eg (int)Parse("1"). Everyone keeps repeating that it will
be too ambiguous without responding to my point. Must be a good point :)

Even when it's not actually ambiguous though, it's likely to be harder
to read - it would take longer to work out what's actually going on.
The overloading rules - which are complicated already - would become
significantly more complicated.

The CLR does support it though IIRC, so I suggest if you still think
it's a good idea, take the Mono compiler and modify it to do what you
want it to do. Use it for a few months and see whether you think it's a
good idea in practice, and then tell us all how you've got on...
 
H

Helge Jensen

Michael said:
"Helge Jensen" <[email protected]> wrote in message
This is going around in circles. Everyone keeps saying it would be overly
ambiguous. I respond by saying that ambiguity can be got around by forcing

Im not saying it would be too ambigous.
the programmer to specify the return type in any case where there is more
than one option, eg (int)Parse("1"). Everyone keeps repeating that it will
be too ambiguous without responding to my point. Must be a good point

The newsgroup is not a good place to teach compiler theory. Take a
course on it.

There are *deep* problems with not only the ambiguity of the language,
but inherent problems with defining the type-validation algorithm.

Have fun.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top