-3

--- UPDATE: ---
TL;DR
While it is not possible to have two methods (in the same context; e.g. in the same class) that differ only by their return type, it is possible to solve the problem a different way:

"Return" the value in an out parameter.

(C#) Bad:

// WON'T COMPILE
int myfunc() { ... }
double myfunc() { ... }

(C#) Good:

void myfunc(out int value) { ... }
void myfunc(out double value) { ... }

--- ORIGINAL QUESTION ---

Yes, this has strong similarities to "Generic interface overloading for methods". Thank you for finding that thread. Note however that it is not "an exact duplicate".

Please read the text bar that is inserted once a Q has been marked as a duplicate - it shows that the intent of "duplicate question" is to mark when a question is an exact duplicate of an existing question, and therefore adds nothing to SO. As I explain below, in response to the three proposed duplicates, this is incorrect (IMO). Instead of marking as duplicate, it would be more helpful to add either an answer or a comment linking to the related Q&A, and explaining the connection.

In that case, OP was working with generics, and it is not clear without delving into the details, that there mistake was trying to only differ by return type. Here, OP is focused on OVERLOADING, and thinks maybe the answer is Generics (it is not).


It is a mistake to consider this a duplicate of Q&A about method signature. Someone (including me, before) who didn't grasp that the solution to "overload + differ only by value returned" is solved by using an "out" parameter, is likely to only be confused by reading that Q&A.

Consider the mindset of someone who doesn't yet understand a topic. There is a difference between a related Q&A, which has answers that could be useful to someone if they were given an ANSWER here, which EXPLAINED how that other Q&A helps, and included a link to that Q&A, and a duplicate Q&A, which is a quite similar thread.


I do not see this as a duplicate of How to use generic method with "out" variable.

The reason it is different is because the goal is different.
Yes, the solution is an out parameter, but the goal is to find a way to overload methods differing only by the value returned.
For many years I have believed that doing so is impossible, because "return value is not part of the method signature."
However, I figured that with all the language enhancements, this might be possible now. (What I did not realize until today, was that it was possible to think about the problem in a different way. I figure I'm not the only one to be obtuse about this. Hence this Q&A.)

That other question only helps someone if they already know that the solution is an out parameter. (That question does not mention either "extension" or "return"/"returned value".)


I have a lot of VB read/write code that looks similar to this:

    Public Structure MyVertex
        Public Position As Vector3
        Public Normal As Vector3
        Public TextureCoordinates As Vector2

        Public Sub Read(br As BinaryReader)
            Position = br.ReadVector3()
            Normal = br.ReadVector3()
            TextureCoordinates = br.ReadVector2()
        End Sub

        Public Sub Write(bw As BinaryWriter)
            bw.WriteVector3(Position)
            bw.WriteVector3(Normal)
            bw.WriteVector2(TextureCoordinates)
        End Sub
    End Structure

where the Read/Write methods are extension methods, e.g.

Public Module ReadWriteExtensions

    <Extension()>
    Public Function ReadVector2(br As BinaryReader) As Vector2
        Dim v2 As New Vector2()

        v2.X = br.ReadSingle()
        v2.Y = br.ReadSingle()

        Return v2
    End Function

    <Extension()>
    Public Function ReadVector3(br As BinaryReader) As Vector3
        ...
    End Function

    <Extension()>
    Public Sub WriteVector2(bw As BinaryWriter, v2 As Vector2)
        ...

    <Extension()>
    Public Sub WriteVector3(bw As BinaryWriter, v3 As Vector3)
        ...
End Module

I know I can use "overloading" of parameter types to simplify the Write methods to have the same name. (I use "WriteT" to distinguish from the built-in BinaryWriter methods, but I could have simply used "Write".):

Public Sub WriteT(bw As BinaryWriter, v2 As Vector2)
    ...

Public Sub WriteT(bw As BinaryWriter, v3 As Vector3)
    ...

So usage becomes easier:

    Public Sub Write(bw As BinaryWriter)
        bw.WriteT(Position)
        bw.WriteT(Normal)
        bw.WriteT(TextureCoordinates)
    End Sub

But I have not done so, because I couldn't see how to do the equivalent to the "Read" methods. The obvious attempt fails because the methods vary only in return type:

<Extension()>
Public Function ReadT(br As BinaryReader) As Vector2
    ...

<Extension()>
Public Function ReadT(br As BinaryReader) As Vector3
    ...

Results in compiler error "Member with the same name or signature is already declared ...".

Is there some way to achieve the desired result?

(An answer for C# would also be useful.)

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • @djv - the reason this is not a duplicate of that question, is because the **goal** here is completely different: for **many years** I have wished that I could code similar "Read" methods the same way I code the "Write" methods. But of course I can't [as long as I was thinking of "return" as the method's return value] because the return value is not part of the signature. Yes, the **solution** is to use an "out parameter", but that is *not the question*. The question is "How can I overload methods that only differ by the value they return?" **overload** being the key word in that question. – ToolmakerSteve Jan 24 '18 at 17:25
  • @djv ... and I'm not the only one who overlooked this at first. Interestingly, the **built-in methods of core .NET Read classes** such as BinaryReader, use the same cumbersome naming I show at first. That's what I copied the style from many years ago. Interesting that they don't use *out* parameters to solve this. Even though they *do* use overloading for the "write" methods! – ToolmakerSteve Jan 24 '18 at 17:29
  • So you posed a Q, and within one minute, you answered "no" and provided an alternative solution, which incidentally is pretty much the same as [this *answer*](https://stackoverflow.com/a/1735754/832052). If I could mark duplicate answer I would. – djv Jan 24 '18 at 17:50
  • Actually I posed a question to myself **ten years ago**, and it took me **ten years** to realize what the answer was. I didn't answer within a minute; I wrote a Q&A about a topic that has bothered me for many years, once I knew the solution. Isn't that what SO is for? To avoid others wasting their time in the same way? [And of course I did a search first; failed to find the suggested "duplicate", because it lacks the key words of my topic.] – ToolmakerSteve Jan 24 '18 at 17:54
  • 2
    Dupes are not about whether the *question* is a duplicate of some other, but whether there is an existing *answer* which will work. Thats why the dupe text is worded as: ***This question already has an answer here:*** If the later/dupe stays around it acts as a "signpost" to funnel other future variants to the answer (assuming they do a search) – Ňɏssa Pøngjǣrdenlarp Jan 24 '18 at 18:03
  • @Plutonix - thanks. However, note that this question is about "overload" and "returned value". The answer to the question is "use an out parameter". The fact that *some different question* also "shows how to use an out parameter" is only partially helpful. What's important here is to make a connection between "overload + returned value" and "out parameter". The linked question does **not** make such a conceptual connection. The answer, in code, looks similar. But at the level of concepts, that answer is quite different: it says "if you already know you want an out parameter, do this". – ToolmakerSteve Jan 24 '18 at 18:33
  • @Plutonix - pragmatically, if this is indeed a "duplicate question", and it receives only downvotes on both Q & A, then it would (and should) be automatically removed at some point in the future. Doing so, would *remove* the association I point out, between "overload + returned value" and "use an out parameter". I suggest that this would remove useful information from SO. I suggest that this demonstrates that *the question* is *not* a duplicate, and that the best action when encountering this situation is either a *comment* or an *answer* that explains how one answer elsewhere is useful. – ToolmakerSteve Jan 24 '18 at 18:44
  • 1
    I commented only to clarify the thing about dupes, not start a new argument about the minutiae of the post (I didnt study it). However, thats not entirely how SO works. A Question *can* be deleted quickly of it is closed - until then we cant VTD. An answer just needs to have a DV before those who can VTD can do so. Otherwise, even a DV'd question with an accepted answer can stay around forever (IIRC - lots of goofy rules related to this). And, answers are about code not concepts. I would hazard that *most* questions dont know what exactly they are looking for when posted (XY problem) – Ňɏssa Pøngjǣrdenlarp Jan 24 '18 at 19:03
  • An all too common example from the cesspool previously known as the VB Tag: user8675309 posts a long winded question about parsing a "complex string". @djv or some other smart kid sees that it is JSON (or HTML) and dupe closes it to a question w/ an answer on how to parse JSON (or HTML). The OP did not even mention JSON (or HTML), so does that mean any dupe link does not apply because of the "context". Of course not, it means the user needed to learn more than just one thing: what it is, how to work with it and probably a new term or two. Q: How do I **X**. A: Do **Y** – Ňɏssa Pøngjǣrdenlarp Jan 24 '18 at 20:39
  • I get XY problems. But sometimes we're not trying to solve a problem - we're trying to understand how something works and what we can or can't do. It's like those covariance compiler errors. We know the compiler won't let us do something. But it's hard to understand why it won't let us until we see what would happen if it did let us. – Scott Hannen Jan 25 '18 at 02:46
  • it's not possible to overload any kind of method solely by return type, so naturally it can't be done for extension methods. as for how to return different types of values for overloaded methods, obviously the _only_ way to accomplish this (since the return type can't be the only different) is to change the parameters (since changing the method name is not overloading). And if you're going to change the parameters, the only sensible approach is to pass an output parameter by reference, i.e. use `out` in C#. And we have a number of Q&A on Stack Overflow that already address this. – Peter Duniho Jan 26 '18 at 04:51
  • @PeterDuniho - FWIW - while that is a wonderful chain of inferences, "obviousness" is in the eye of the beholder. I've kept this Q around, despite the heavy downvoting and the evidence that it seems to have not been a helpful signpost (only one upvote), because I was stuck in this blind spot for quite a while. Despite years of experience in a variety of OO languages. The existence of the other Q&As never did me any good, because there was nothing in their wording that helped me change the problem definition from "a different return type => can't do" to "return value a different way => can do". – ToolmakerSteve Jan 28 '20 at 02:53
  • @PeterDuniho ... most importantly, I've encountered the fact "overloaded methods can't vary only by return type" repeatedly. In none of those encounters, did someone bother to say "... so don't do it that way, instead use an `out` parameter". – ToolmakerSteve Jan 28 '20 at 03:02

1 Answers1

0

If you could have methods that varied only by return values, then how would you know for sure which method you were calling if the variable to which the result was assigned was implicitly typed or if multiple return types were assignable to the variable?

For example, suppose you had these three methods:

Public Function GetResult() As Object
   Return new Object()
End Function

Public Function GetResult() As SomeClass
    Return new SomeClass()
End Function

Public Function GetResult() As SomeOtherClass
    Return new SomeOtherClass()
End Function

If you do this:

Dim result = whatever.GetResult()

What will result be - Object, SomeClass, or SomeOtherClass?

Even if you could do this:

Dim result as SomeClass = whatever.GetResult()

What if SomeOtherClass inherits from SomeClass? Either one would be valid, so how would you know which one was returned?

But the worst part is that in these scenarios, if you could do this and the compiler attempted to infer which method you meant to call, then you could remove a method, your code would still compile, but removing that method would cause your code to call a different method. That's bad. If we remove the method our code calls, we want a compiler error. We don't want it to transparently guess at the next best method to call.

So one reason (I'm sure there others) is that if signatures could vary only by return type then the selection of methods could be ambiguous, harder to follow, and could change without warning.


On the other side, what is gained by ensuring that two methods have the same name? Giving things different names is a wonderful opportunity to add meaning to our code, and we should do it whenever we can. In fact, in cases where we are allowed to duplicate names, we often shouldn't. For example, we could decide that every method's first parameter should be a, the second should be b, etc. The compiler won't stop us from using a over and over again. But if we did we'd miss out on giving our parameters meaningful names that help others follow the code.

Or we could give all of our classes the same name, but in different namespaces. No compiler errors. But naming things is good, so if the compiler forces us to disambiguate a little with different names, that's also good.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62