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
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
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.
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.
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();
}
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.
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);