Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I compare sbyte to all the other numeric types *except* ulong?

Tags:

c#

.net

clr

You can do >, <, ==, etc. comparisons between sbyte and byte, int, uint, short, ushort, long, double, and float. But not ulong.

My brain is exploding. Can anyone explain why sbyte can be compared to uint but not ulong?

public bool sbyte_ulong_compare(sbyte x, ulong y)
{
    return x < y;  // compiler error CS0019
}

Also, using unchecked doesn't make things work any better. Brain melting.

Another edit. This works:

public bool sbyte_ulong_compare(sbyte x, ulong y)
{   
    //
    // returns x < y
    //
    if (x < 0)
        return true;

    if (y > 127)
        return true;

    return ((long)x < (long)y);
}

1 Answers

dthorpe and Jon's answers are close but not quite correct.

The correct reasoning is as follows.

The specification states:

For an operation of the form x op y, where op is a comparison operator, overload resolution is applied to select a specific operator implementation.

OK, what are the operator implementations that overload resolution has to work with? They are:

bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);
bool operator <(float x, float y);
bool operator <(double x, double y);
bool operator <(decimal x, decimal y);

Plus the enum less-than operator for all enumerated types, plus the lifted-to-nullable versions of each of the foregoing.

Overload resolution must first eliminate inapplicable operators, and then from the remaining set of applicable operators, determine the best operator.

The int, uint, long and enum operators (and their lifted forms) are all eliminated because ulong does not implicitly convert to those types.

The uint and ulong operators (and their lifted forms) are all eliminated because sbyte does not implicitly convert to those types.

That leaves

bool operator <(float x, float y);
bool operator <(double x, double y);
bool operator <(decimal x, decimal y);

and their lifted forms. We must now determine the best operator from those six.

What do we mean by "best"? When comparing two operators, the one with the more specific operand types is the better one. By "more specific" I mean that "Tiger" is more specific than "Animal" because all Tigers are convertible to Animal but not all Animals are convertible to Tiger.

Clearly the unlifted forms are better than all of the corresponding lifted forms. A non-nullable type is more specific than its corresponding nullable type because a non-nullable type is always convertible to its nullable type, but not vice-versa. We can eliminate the lifted forms.

That leaves three. Which of those three is the best?

float is more specific than double. Every float is convertible to double, but not every double is convertible to float. Therefore double is eliminated. That leaves two.

bool operator <(float x, float y);
bool operator <(decimal x, decimal y);

Which of these is the best? There is no implicit conversion from float to decimal. There is no implicit conversion from decimal to float. Therefore neither is better than the other.

Therefore no best operator can be determined. Overload resolution fails.

We have decided to report a generic error message that simply says that there is no such operator that does what you want, rather than giving the seemingly bizarre and confusing error message "operator overload resolution failed because float is neither better nor worse than decimal". I think that is a reasonable design choice.

like image 74
Eric Lippert Avatar answered Sep 13 '25 20:09

Eric Lippert