C# Method overloading resolution and user-defined implicit conversions
Asked Answered
G

1

10

I try to find some information about method overloading resolution in case of presence of user-defined implicit conversions and about conversions priority.

This code:

class Value
{
    private readonly int _value;
    public Value(int val)
    {
        _value = val;
    }

    public static implicit operator int(Value value)
    {
        return value._value;
    }

    public static implicit operator Value(int value)
    {
        return new Value(value);
    }
}

class Program
{
    static void ProcessValue(double value)
    {
        Console.WriteLine("Process double");
    }

    static void ProcessValue(Value value)
    {
        Console.WriteLine("Process Value");
    }

    static void Main(string[] args)
    {
        ProcessValue(new Value(10));
        ProcessValue(10);
        Console.ReadLine();
    }
}

Produces output:

Process Value
Process Value

So, It looks like compiler chosen user-defined conversion instead of built-in implicit conversion from int to double (built-in conversion is implicit due to info from this page https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/implicit-numeric-conversions-table).

I tried to find something about this in specification, but with no success.

Why compiler selected ProcessValue(Value value) instead of ProcessValue(double value)

Goose answered 12/11, 2018 at 13:22 Comment(5)
It will not do two conversions, so it won't convert it to double and then double to Value, it will instead look for a direct cast/conversion.Randi
@LasseVågsætherKarlsen: The OP isn't expecting it to do two conversions. They're just expecting it to do a conversion from int to double (or perhaps treat it as ambiguous)Meteoritics
At the moment, this looks like a compiler or spec bug to me. I think it should be ambiguous.Meteoritics
@Jon Skeet Or built-in conversion should be first in list of possible conversions. It looks like now it is able to change semantics of existing code just by adding user-defined conversionGoose
@DanielVlasenko: Oh you can definitely change the semantics of existing code just by adding a user-defined conversion. That's easy to give examples of. But this should at least be explicable in the spec...Meteoritics
D
4

In this case, the conversion between int -> double takes lower precedence because a user-defined implicit conversion between int -> Value exists.

See: User-defined operator implementations always take precedence over predefined operator implementations.

Defant answered 12/11, 2018 at 13:27 Comment(8)
Just for some extra context for OP: 10 is of type int while 10.0 is of type double.Blazer
Now that I read the OP question more carefully, I think he knows this. I'll keep this answer around for a bit just to prevent others to answer the same .Defant
Yes, sir, I know about literal types. And of course if I'll use 10.o instead of 10 ProcessValue(double) will be called. My question is about conversion priority, why i->double is lower than user-defined int->ValueGoose
That "precedence" is only used within operator overload resolution, which isn't being used here. In this case, both methods are applicable, and the rules for "better function member" should apply. If the intention is for a user-defined operator implementation to "win" here, it should be shown in "better conversion target". I really don't think the spec handles this situation at the moment.Meteoritics
Ouch, you are right. But reading the documentation I think it does handles this by stating that implicit conversion for arguments matters, and for tie-breaking the more specific parameter types are better (7.5.3.2).Defant
So yes, we have to choose which conversion to use and we see this sentence about user-defined conversions and we could guess that it is also could be applied to method overload resolution. But. It is still about resolution of conversion operators. int->double is not a conversion operator as I understand, it is a built-in conversion and int->Value is user-defined conversion defined through conversion operator overloading. If int->double is an conversion operator by spec, than this is an answerGoose
the link is brokenFoscalina
@DavidLechner thank you, replaced it with a new oneDefant

© 2022 - 2024 — McMap. All rights reserved.