4

If I have this code, this will compile and work as it should:

class MyNumber // Just a class.
{
    static public explicit operator MyNumber(byte b)
    {
        return new MyNumber();
    }
}

Decimal d = new Decimal();
MyNumber c1 = (MyNumber)d;

Perhapse some people are a bit of a surprise, since there is no existing explicit cast from a decimal to MyNumber. But since there is a explicit cast from decimal to byte and there is also a explicit cast from a byte to MyNumber, the compiler is kind enough to insert that extra explicit cast for me.

In short: If the programmer uses an explicit cast, the compiler takes the freedom to search for other explicit cast to get the whole thing going.

So... I tried the same thing with my own classes. Instead of byte and decimal, I used MyByte and Mydecimal. The code looks like this:

class MyDecimal // Simulates a decimal.
{
    static public explicit operator MyByte(MyDecimal a) // Just like in a decimal.
    {
        return new MyByte();
    }
}

class MyByte // Simulates a byte.
{
}

class MyNumber // Just a class.
{
    static public explicit operator MyNumber(MyByte b)
    {
        return new MyNumber();
    }
}

MyDecimal d = new MyDecimal();
MyNumber c2 = (MyNumber)d; // <== Will not compile!

The last line will not compile. It gives the error: "Cannot convert type 'DoubleExplicitCasts.Program.MyDecimal' to 'DoubleExplicitCasts.Program.MyNumber'". Well... why not???

So my question is: Why do the explicit operators inside .NET system get a special treatment and my user explicit operators do not?

EDIT
I know this code is not functional and values are not transfered from one instance to another, but that is beside the point.

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54

2 Answers2

2

Well, trivially, because that's how it's defined by the C# standard.

From section 6.4.3:

Evaluation of a user-defined conversion never involves more than one user-defined or lifted conversion operator. In other words, a conversion from type S to type T will never first execute a user-defined conversion from S to X and then execute a user-defined conversion from X to T.

As to why they chose to limit the conversions in that way - that's a different matter. I'm going to propose two possible reasons:

  1. It would allow the possibility of too many "surprising" conversions
  2. It would make the compilation process too slow (possible combinational explosion)

but that's just conjecture on my part.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
2

IMO, that would lead to "happy debugging" and really, really complicated and non-obvious code.

Just imagine 3 or more levels of such user-defined conversions, and how would you search for error, caused by conversion in the middle (e.g such conversion was introduced by mistake or not supposed to be used in that situation).

Thanks God such behaviour is not supported.

illegal-immigrant
  • 8,089
  • 9
  • 51
  • 84
  • Well... it **is** supported: for explicit system operators. – Martin Mulder May 10 '13 at 12:57
  • You asked about user-defined conversions, I mentioned user-defined conversions. I thought it was clear, will add to the answer – illegal-immigrant May 10 '13 at 12:59
  • Thanks for changing it. Besides that: I cannot entierly agree to your opinion. Delegates, Generics, LINQ, etc. can also create very complex software to debug. In my opinion a good programmer should know how to write code and how to debug. I think it is patronizing to not allow it (by the developers of C3) when they see "their" operators as "good" and "trustworthy" and "our" operators as "difficult to debug". – Martin Mulder May 10 '13 at 13:25