Here there be tigers - operator overloading and conversions

I came across a discussion in the last few days that I thought I would share with you. It concerns the following code:

class Utility
{
    public void Process(object o);
    public void Process(string s);
}

and then a call to Process that passed in a string.

C# does permit this sort of overloading, and it has some complex rules (see 7.4.2.2 in the spec for the details) to decide which is the better conversion, and therefore which function will be called. The rules are complex - I wrote our compiler conformance suites for this, and I still have to diagram it to get it right.

It's string here, which probably didn't surprise anybody. For classes, the rules will prefer the more-derived/more-specific type.

But what about the following:

public void Process(int i);
public void Process(uint j);
...
ushort x = 55;
inst.Process(x);

Which method is called?

The answer is “Process(int i)“, and this happens because, the language always prefers conversions to the signed types over conversions to unsigned types (a preference one way or the other is required to make things coherent in the presence of both signed and unsigned types).

Behavior like this can be more than a little confusing to users of a class. As language designers, we have to make sure that there's a well-defined behavior in cases such as these, but that doesn't mean that you have to create such cases.

My advice:

Think deeply before overloading on two types that have conversions defined between them. If you do need to overload on numeric types - say you're writing something like String.Format - then you need to overload on all the types.