views:

181

answers:

6

Method overloading allows us to define many methods with the same name but with a different set of parameters ( thus with the same name but different signature ).

Are the two methods overloaded?

class A
{
    public static void MyMethod<T>(T myVal) { }
    public static void MyMethod(int myVal) { }
}

thank you

EDIT:

Shouldn't statement A<int>.MyMethod(myInt); throw an error, since constructed type A<int> has two methods with the same name and same signature?

+2  A: 

Yes, they are. They will allow code as such:

A.MyMethod("a string"); // calls the generic version
A.MyMethod(42);  // calls the int version
Fredrik Mörk
+4  A: 

Yes. MyMethod(int myVal) will be called when the type of the parameter is an int, the generic overload will be called for all other parameter arguments, even when the parameter argument is implicitly convertible to (or is a derived class of) the hardcoded type. Overload resolution will go for the best fit, and the generic overload will resolve to an exact match at compile time.

Note: You can explicitly invoke the generic overload and use an int by providing the type parameter in the method call, as Steven Sudit points out in his answer.

short s = 1;
int i = s;
MyMethod(s); // Generic
MyMethod(i); // int
MyMethod((int)s); // int
MyMethod(1); // int
MyMethod<int>(1); // Generic**
MyMethod(1.0); // Generic
// etc.
Anthony Pegram
I think the second part is not strictly true: check out my answer.
Steven Sudit
@Steven, an explicit invocation of the generic overload is a different matter entirely. I'll make a note.
Anthony Pegram
could you read my edit?
@aspnetonc, regarding your question of MyMethod(int i) versus MyMethod<int>(T t) and how it compiles in an unambiguous manner, you may wish to visit Eric Lippert's blog (google it, not hard to find) and use the contact link. Pose your question there or provide a link to here. He'll likely chime in if someone doesn't provide a good explanation in the interim.
Anthony Pegram
The short version is the IL shows a call to MyMethod(int32) if you do make the call `MyMethod(1)`, `MyMethod<int32>` if you use `MyMethod<int>(1)`, and `MyMethod<float64>` if you use `MyMethod(1.0)`. I'm no IL expert, but it looks like the resolved type becomes part of the method name, removing the ambiguity. I could be completely off base, though.
Anthony Pegram
+1  A: 

Yes. They have the same name "MyMethod" but different signatures. The C# specification, however, specifically handles this by saying that the compiler will prefer the non-generic version over the generic version, when both are options.

Reed Copsey
+1  A: 

Yes. Off the top of my head, if you call A.MyMethod(1);, it will always run the second method. You'd have to call A.MyMethod<int>(1); to force it to run the first.

Steven Sudit
+1  A: 

Yes, they are overloaded. The compiler is supposed to prefer explicit method signatures against generic methods if they are available. Beware, however, that if you can avoid this kind of overload you probably should. There have been bug reports with respect to this sort of overload and unexpected behaviors.

https://connect.microsoft.com/VisualStudio/feedback/details/522202/c-3-0-generic-overload-call-resolution-from-within-generic-function

Joel Etherton
Actually, the link goes to a *mistaken* bug report. The reporter just didn't understand that explicit methods beat out generics for overloading purposes. So, while you may have a point about this being a complexity that we might wish to avoid, I don't think it's due to any actual bugs.
Steven Sudit
The issues people run into are scenarios where you have constraints (not part of the signature!) or situations where you have a `Reptile` and a `Lizard : Reptile`, and `Foo<T>(T t)` gets called for `Lizard lizard` rather than `Foo(Reptile reptile)`. The reason? The generic will compile to an exact match for `Lizard` rather than using a close-enough match with `Reptile`.
Anthony Pegram
hi, could you see my edit?
@Anthony: Good point. I guess the desired behavior would be possible only if we first upcast the `Lizard` to `Reptile`, but it can be more subtle than that, as when we're dealing with implicit conversions among int types.
Steven Sudit
+11  A: 

Are the two methods overloaded?

Yes.

Shouldn't statement A<int>.MyMethod(myInt); throw an error, since constructed type A<int> has two methods with the same signature?

The question doesn't make sense; A is not a generic type as you have declared it. Perhaps you meant to ask:

Should the statement A.MyMethod(myInt); cause the compiler to report an error, since there are two ambiguous candidate methods?

No. As others have said, overload resolution prefers the non-generic version in this case. See below for more details.

Or perhaps you meant to ask:

Should the declaration of type A be illegal in the first place, since in some sense it has two methods with the same signature, MyMethod and MyMethod<int>?

No. The type A is perfectly legal. The generic arity is part of the signature. So there are not two methods with the same signature because the first has generic arity zero, the second has generic arity one.

Or perhaps you meant to ask:

class G<T> 
{
    public static void M(T t) {}
    public static void M(int t) {}
}

Generic type G<T> can be constructed such that it has two methods with the same signature. Is it legal to declare such a type?

Yes, it is legal to declare such a type. It is usually a bad idea, but it is legal.

You might then retort:

But my copy of the C# 2.0 specification as published by Addison-Wesley states on page 479 "Two function members declared with the same names ... must have have parameter types such that no closed constructed type could have two members with the same name and signature." What's up with that?

When C# 2.0 was originally designed that was the plan. However, then the designers realized that this desirable pattern would be made illegal:

class C<T> 
{
    public C(T t) { ... } // Create a C<T> from a given T
    public C(Stream s) { ... } // Deserialize a C<T> from disk
}

And now we say sorry buddy, because you could say C<Stream>, causing two constructors to unify, the whole class is illegal. That would be unfortunate. Obviously it is unlikely that anyone will ever construct this thing with Stream as the type parameter!

Unfortunately, the spec went to press before the text was updated to the final version. The rule on page 479 is not what we implemented.

Continuing to pose some more questions on your behalf:

So what happens if you call G<int>.M(123) or, in the original example, if you call A.MyMethod(123)?

When overload resolution is faced with two methods that have identical signatures due to generic construction then the one that is generic construction is considered to be "less specific" than the one that is "natural". A less specific method loses to a more specific method.

So why is it a bad idea, if overload resolution works?

The situation with A.MyMethod isn't too bad; it is usually pretty easy to unambiguously work out which method is intended. But the situation with G<int>.M(123) is far worse. The CLR rules make this sort of situation "implementation defined behaviour" and therefore any old thing can happen. Technically, the CLR could refuse to verify a program that constructs type G<int>. Or it could crash. In point of fact it does neither; it does the best it can with the bad situation.

Are there any examples of this sort of type construction causing truly implementation-defined behaviour?

Yes. See these articles for details:

http://blogs.msdn.com/b/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Eric Lippert
"The generic arity is part of the signature. So there are not two methods with the same signature because the first has generic arity zero, the second has generic arity one." Just to be sure – if we define void MyMethod<T>(){…}, then MyMethod represents the name of a method while generic arity is just a part of signature, but not part of the method name?
@aspnetonc: Correct. Methods can have the same name, but every method must have a unique *signature*. The C# language specification defines the signature of a method as the combination of its name, generic arity, and parameter types (and notes that signatures that differ only by one being "out" and another being "ref" are considered to be the same signature.) The CLR has a slightly different definition of "signature" as it also considers return types and modopt / modreq modifers on parameter types and return types as part of the signature.
Eric Lippert
@Eric: Do you know why the return type overloading isn't exposed to C#? Do you think it wouldn't be as useful? I remember a case where I thought it would be useful to have.
Joan Venge
@Joan: It makes overload resolution extremely difficult. Suppose you have int M(int x) and string M(string x). You call M(N(q)) and what do you do to do overload resolution on M? Well, first you have to consider the type of the argument N(q). If resolving that depends on the return type then you have a chicken-and-egg problem; the return type of N could be string or int, depending on which M is chosen, *which is precisely what we are attempting to determine in the first place*.
Eric Lippert
@Joan: Now, lambdas DO have this problem; how you type-bind the inside of a lambda depends on its context, which can depend on the inside of the lambda. Getting that to work efficiently in common cases took me the better part of a year, and there are still pathological cases where you have to do an exponential enormous number of bindings. That situation is confined to deeply nested lambdas, which are rare. Nested function calls are common. In general, we always want to reason from the *inside* to the *outside* of an expression, and not try to go both ways.
Eric Lippert
@Eric: Thanks Eric. Really nice to read about this topic. For the M return overload case, I see what you mean. But you said it becomes extremely difficult, but not impossible, so can this be really resolved if need be? I just thought there would be no way around this M(N(q)) problem.
Joan Venge
@Joan: It is doable; we know this because we do it with lambdas. But it means that if you have function calls that nest n deep, each of which has m overloads, then there are m-to-the-n possibilities that overload resolution must consider. We must consider *all* of them because if none of them work, then we must have tried all of them, and if one of them works, then we need to know if there is a second (so that we can give an ambiguity error), and the second one could be the last one. It makes simple programs take arbitrarily long to compile, so we're not going there.
Eric Lippert
@Eric: Thanks Eric, fascinating info. Really like to think about these kind of hard problems.
Joan Venge
"The CLR has a slightly different definition of "signature" as it also considers return types and modopt / modreq modifers on parameter types and return types as part of the signature" If C# and CLR have different definition of signature, does that mean I should only write method overloads that conform to CLR definition of signature?
@User437291: I do not understand the question. It sounds like you are asking "should I not do something impossible?" - whether you *should* or *should not* do something impossible is a moot point; you're not *going* to do something impossible regardless of whether it's moral or not. Suppose the answer is "sure, go ahead, write a method overload that does not conform to the CLR rules for method signature uniqueness". How would you even begin to do that? Are you planning on writing your own metadata emitter, or what exactly?
Eric Lippert
Yeah, it was a stupid question since application doesn't compile if class defines two methods that differ only in return types. Still, I find it confusing why C# and CLR have different definitions of what makes a method signature unique.
Eric Lippert
" ... don't you think?" I don’t know, you’re the big chief, while I’m more on a retarded side, so I’m just going to nod in agreement how this should make perfect sense even to those ( me ) that know crap about CLR/IL
@user437291: I'm happy to expand on any of these points if there's something confusing, but in that case perhaps you'd do better to *post a question* rather than continue to have this conversation five hundred characters at a time.
Eric Lippert
No need. My primary interest at this point is getting to know C# first and perhaps later ( after I have a brain transplant ) CLR/IL also. Thank you for helping me