Search code examples
c#compiler-construction

How does the C# compiler handle overloading explicit cast operators?


The compiler should translate this code:

public static explicit operator Int64(MyNumber n)
{
    return n.ToInteger();
}

public static explicit operator Double(MyNumber n)
{
    return n.ToDouble();
}

to two methods that have the same name and signature but differ only by their return type, e.g.

public static Int64 ExplicitCast(MyNumber n)
...

public static Double ExplicitCast(MyNumber n)
...

However, we are not allowed to have methods that differ only by their return type. What happens behind the curtains?


Solution

  • Technically the CLS (the Common Language Specification, a specification that specify a subsect of the .NET virtual machine that all .NET languages should support) says that the name of the explicit cast method should be op_Explicit (see for example http://goo.gl/wn8dHq).

    The limitation that you can't have multiple methods with the same name and only different return types is a limitation of C#. The IL language (that is the language of the .NET virtual machine) doesn't have this limitation.

    See for example: https://stackoverflow.com/a/442100/613130

    Some languages (such as MSIL), however, do allow overloading by return type. They too face the above difficulty of course, but they have workarounds, for which you'll have to consult their documentation.

    and https://blogs.msdn.microsoft.com/abhinaba/2005/10/07/c-cil-supports-overloading-by-return-type/

    However, CIL does support overloading methods by return types, even though C#, VB does not . To implement convertion operator overloading C# compiler uses this feature (I know of one usage and I’m sure that there are more :) )

    (that is exactly the case asked here)

    If you want to look at the ECMA-335 standard:

    I.8.11.1 Method definitions

    The method signature defines the calling convention, type of the parameters to the method, and the return type of the method

    If you are interested to know how the method can be called... Well... Clearly if the IL language supports overload by return type, then its call instruction must support it :-)

    For example http://goo.gl/CS4FPb:

    call int64 MyNumber::op_Explicit(class MyNumber)
    

    vs

    call float64 MyNumber::op_Explicit(class MyNumber)
    

    Note that CLS normally forbids overloading only based on return type... But it has an exception for op_Implicit (the implicit cast operator) and op_Explicit (the explicit cast operator) (from the same ECMA-335 file):

    CLS Rule 38: Properties and methods can be overloaded based only on the number and types of their parameters, except the conversion operators named op_Implicit and op_Explicit, which can also be overloaded based on their return type.