10

Why is integer == null a valid boolean expression in C#, if integer (variable of type int) is not nullable? (I'm not against it, in fact I like it, but I didn't know it was possible)

Guillermo Gutiérrez
  • 17,273
  • 17
  • 89
  • 116
  • 1
    You do get a warning, something along the lines of "expression is always false". As to why it's *allowed*, i.e., does not result in a compile time error... I suppose it's for the same reason this is allowed; `while(true)` – Ed S. Jun 18 '13 at 21:46
  • The C# compiler will at compile time optimize this to false when compiled in release mode (a `ldc.i4.0` ends up being in IL). – vcsjones Jun 18 '13 at 21:50
  • 1
    possible duplicate of [C# okay with comparing value types to null](http://stackoverflow.com/questions/1972262/c-sharp-okay-with-comparing-value-types-to-null) – Eric Lippert Jun 18 '13 at 22:50

2 Answers2

19

Although int itself is non-nullable, there's an implicit conversion to int?, which is nullable.

At that point, if the struct declares an == operator with the same type on both sides, then that's lifted to work with nullable types too.

So this doesn't compile:

public struct Foo {}

class Test
{
    static void Main()
    {
        Foo x = new Foo();
        if (x == null)
        {
            ...
        }
    }
}

... but if you give Foo some operators, it does compile, and without a warning:

public struct Foo
{
    public static bool operator ==(Foo x, Foo y) { return true; }
    public static bool operator !=(Foo x, Foo y) { return false; }
    public override bool Equals(object x) { return false; }
    public override int GetHashCode() { return 0; }
}

The operator invocation isn't included in the compiled code, because the compiler knows that the RHS is null.

So code of the form above (where Foo can be replaced by any non-nullable struct) has one of three outcomes with the MS C# 5 compiler:

  • Warning CS0472 (e.g. with int)
  • Error CS0019 (custom types which don't overload ==)
  • Clean compilation (custom types which overload ==, including Guid and DateTime)

It's not clear to me why the compiler treats some "known" types differently to normal structs though. EDIT: As noted by Eric in comments, this is a known bug in the C# compiler, which is hopefully fixed in Roslyn.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Damn, that's weird! Maybe structs are the exception? – Guillermo Gutiérrez Jun 18 '13 at 21:54
  • And trying to create your own implicit operator to convert it to `Nullable` (eg `public static implicit operator Nullable(Foo f)`) fails with compiler error [CS0555](http://msdn.microsoft.com/en-us/library/b8xz60wc.aspx). – Joshua Jun 18 '13 at 21:56
  • 10
    Re: it's not clear why known types are different from user defined types: it is a bug, probably introduced by me when I was refactoring parts of the compiler during C# 3.0. For some unclear reason the bug has never been fixed even though we've known about it for a long time now. I seem to recall I fixed it in Roslyn before I left but I don't recall exactly. – Eric Lippert Jun 18 '13 at 22:45
  • 2
    I also note that this is a duplicate of http://stackoverflow.com/questions/2177850/guid-null-should-not-be-allowed-by-the-compiler/2177971#2177971 and http://stackoverflow.com/a/1972317/88656 – Eric Lippert Jun 18 '13 at 22:47
  • 1
    And this one also has some similar analysis: http://stackoverflow.com/questions/2464097/why-doesnt-the-compiler-at-least-warn-on-this-null/2481017#2481017 – Eric Lippert Jun 18 '13 at 22:49
1

As Ed mentions there's a warning, but the warning alludes to the reason: int can be auto-casted to int?, and null is a valid value for a variable of type int?.

Shlomo
  • 14,102
  • 3
  • 28
  • 43