Operator “>” cannot be applied to type ‘ulong’ and ‘int’

I’ve been experimenting with this, using ILSpy to examine the output, and this is what I’ve discovered.

Obviously in your second case this is an error – you can’t compare a ulong and an int because there isn’t a type you can coerce both to. A ulong might be too big for a long, and an int might be negative.

In your first case, however, the compiler is being clever. It realises that const 1 > const 32 is never true, and doesn’t include your if statement in the compiled output at all. (It should give a warning for unreachable code.) It’s the same if you define and use a const int rather than a literal, or even if you cast the literal explicitly (i.e. (int)32).

But then isn’t the compiler successfully comparing a ulong with an int, which we just said was impossible?

Apparently not. So what is going on?

Try instead to do something along the following lines. (Taking input and writing output so the compiler doesn’t compile anything away.)

const int thirtytwo = 32;
static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > thirtytwo;
    Console.WriteLine(gt);
}

This will compile, even though the ulong is a variable, and even though the result isn’t known at compile time. Take a look at the output in ILSpy:

private static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > 32uL;        /* Oh look, a ulong. */
    Console.WriteLine(gt);
}

So, the compiler is in fact treating your const int as a ulong. If you make thirtytwo = -1, the code fails to compile, even though we then know that gt will always be true. The compiler itself can’t compare a ulong to an int.

Also note that if you make x a long instead of a ulong, the compiler generates 32L rather than 32 as an integer, even though it doesn’t have to. (You can compare an int and a long at runtime.)

This points to the compiler not treating 32 as a ulong in the first case because it has to, merely because it can match the type of x. It’s saving the runtime from having to coerce the constant, and this is just a bonus when the coercion should by rights not be possible.

Leave a Comment