Really impossible to use return type overloading?

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.


Solution 1:

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

Solution 2:

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.

Solution 3:

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