Reputation: 105067
I made a small DLL in MSIL with two methods:
float AddNumbers(int, int)
int AddNumbers(int, int)
As some of you might know, MSIL allows you to make methods that have the same arguments as long as you have different kinds of return types (what is called return type overloading). Now, when I tried to use it from c#, as I was kinda expecting, it fired an error:
float f = ILasm1.MainClass.AddNumbers(1, 2);
The error is:
The call is ambiguous between the following methods or properties: 'ILasm1.MainClass.AddNumbers(int, int)' and 'ILasm1.MainClass.AddNumbers(int, int)'
Is c# really incapable of distinguishing between different return types? I know I cannot program methods that have as only difference different return types, but I always kinda assumed it would know how to handle it.
Upvotes: 12
Views: 4969
Reputation:
ECMA-334 C# Section 8.7.3
The signature of a method consists of the name of the method and the number, modifiers, and types of its formal parameters. The signature of a method does not include the return type.
You could use a generic method:
T AddNumbers<T>(int a, int b)
{
if (typeof(T) == typeof(int) || typeof(T) == typeof(float))
{
return (T)Convert.ChangeType(a + b, typeof(T));
}
throw new NotSupportedException();
}
Upvotes: 22
Reputation: 2217
How about passing in the return type as a parameter using pointers?
void AddNumbers(int a, int b, float *ret){
*ret = (float)(a + b);
}
void AddNumbers(int a, int b, int *ret){
*ret = (int)(a + b);
}
Calling it would become something like this:
int a;
float b;
AddNumbers(1, 2, &a);
AddNumbers(1, 2, &b);
Upvotes: -3
Reputation: 89661
MSIL being able to hold both methods in the same assembly has nothing to do with the compiler determining which one to call.
Covariant return types have been discussed for many years, they are partially allowed in Java, C++ has a special case, and the C# designers have added some minor changes to 4.0.
For your toy problem, there are simple typical solutions. For instance, your float AddNumbers(int, int)
is likely always to be the same as (float) AddNumbers(int, int)
, in which case there is no need for the second function. Typically that case is handled with generics: <T> AddNumbers(<T> n1, <T> n2)
, so you'd end up with float AddNumbers(float, float)
and int AddNumbers(int, int)
.
A real-life scenario is more likely to be where you have different representations you want to return but you don't want to rename the method. In the inheritance/override use case, you can also solve this somewhat with generics.
In the few cases, where I've wanted to do as you want, it's actually turned out better to name the methods more appropriately since it is more readable and maintainable in the long run.
This was also discussed already here.
The case in MSIL/C# at http://blogs.msdn.com/abhinaba/archive/2005/10/07/478221.aspx is special because they are explicit conversion operators.
Upvotes: 2
Reputation: 15515
Like everyone else has said, no C# doesn't support this. In fact, the reason IL supports this, is because you have to be explicit about the return types, just like the parameters. For instance, in IL you'd say
ldarg.0
ldarg.1
call int AddNumbers(int, int)
IL doesn't really have a notion of method overloading: float AddNumbers(int, int)
has no relation to int AddNumbers(int, int)
whatsoever, as far as IL is concerned. You have to tell the IL compiler everything in advance, and it never tries to infer you intent (like higher level languages like C# do).
Note that most .NET languages and C# make one exception to return type overloading: conversion operators. So
public static explicit operator B(A a);
public static explicit operator C(A a);
are compiled to
public static B op_Explicit(A a);
public static C op_Explicit(A a);
Because this is such a specific corner case which has to be supported for primitive types (such as int -> bool) and reference type conversions (otherwise you'd get a very pedantic language), this is handled, but not as a case of method overloading.
Upvotes: 18
Reputation: 25371
No, there's no way to do that. In fact, except in C++ with templates, no language is supporting it. This is just plainly too dangerous. And again, what if you write
var a = AddNumbers(1, 1);
what type a
suppose to be?
Or what if you call it like
double a = AddNumbers(1, 1);
or even
AddNumbers(1, 1);
what version should it call?
Remember, there's quite complicate rules about how one type can be implicitly converted to another. Let's take a look at simple program that doesn't compile
class Program
{
static int parse(int a) { return a; }
static float parse(float a) { return a; }
static void Main(string[] args)
{
double a = parse(1.0);
}
}
If you try to compile it, compiler will give you an error
error C2668: 'parse' : ambiguous call to overloaded function
could be 'float parse(float)'
because 1.0 has type double
and compiler really doesn't know what type to choose between int
and float
so it asks you to give it a hint. So you can just go ahead and convert an argument before calling a function.
But if it was return type that function is overloaded by, how do you do that then? There's simply no way of doing it.
Upvotes: 1
Reputation: 273219
Yes it really is not possible in C#, I know C++ does not allow this either, it has to do with the way a statement is interpreted:
double x = AddNumbers(1, 2);
The rule here is that the assignment is right-associative, meaning the expression on the right is completely evaluated first and only then is the assignment considered, applying implicit conversions where necessary.
There is no way for the compiler to determine which version is most appropriate. Using some arbitrary rule would just invite hard to find errors.
It is related to this simple statement:
double y = 5 / 2; // y = 2.0
Upvotes: 18
Reputation: 532435
The problem is that there is an automatic conversion from int to float so it really doesn't know what you intended. Did you intend to call the method that takes two ints and returns an int, then convert it to float or did you intend to call the method that takes two ints and returns a float? Better to have a compiler error than to make the wrong choice and not let you know until your application breaks.
Upvotes: 4