14

This is not to solve any particular problem. Simply a compiler question.

Why does the following code not result in compile error? It's comparing a reference type to primitive type. Both null and false have to to be interpreted into something for the compiler to do comparison. Or is the parser simply scanning for such pattern and replace it with false?

if(null == false) { }
weilin8
  • 2,975
  • 3
  • 32
  • 36
  • 4
    Value type or not, `false` is still an object. It will probably be boxed for the comparison. – cHao May 04 '13 at 00:43
  • 6
    @cHao: Your conjecture is incorrect. The equality operator is specifically designed to avoid boxing; read the specification for details. – Eric Lippert May 04 '13 at 14:41

3 Answers3

28

It's legal because the lifted comparison operator is used. If you compare a bool to a null, both the bool and null get implicitly converted to Nullable<bool> and the comparison operator for Nullable<bool> ends up being used. You get a warning because obviously, it is always false.

Tejas Sharma
  • 3,420
  • 22
  • 35
  • 4
    I like your answer better, as it explains the _why_ it is allowed and _how_ it works. Instead of just stating the obvious. By the way, the compiler (in Debug-mode with optimizations off) doesn't even try to emit it. It simply emits `false` into the code. – Daniel A.A. Pelsmaeker May 04 '13 at 01:40
  • This is incorrect, per section 7.9.10 of the spec (equality operators and null). This explanation only applies in the case where, for `null == x`, `x` is a nullable type. The spec states this is equivalent to `x.HasValue`. Since the literal `false` is not a nullable type, the reason this is legal is not related to the lifted comparison operator. – drf May 04 '13 at 02:21
  • 4
    `false` might not be a nullable type, but it is of type `bool` and there is an implicit conversion between `bool` and `bool?` – Tejas Sharma May 04 '13 at 02:23
  • 4
    Also, here's a post by Eric Lippert on this topic http://stackoverflow.com/questions/1972262/c-sharp-okay-with-comparing-value-types-to-null – Tejas Sharma May 04 '13 at 02:24
  • 5
    This is the only correct answer posted. – Eric Lippert May 04 '13 at 14:46
  • As endorsed by Eric Lippert. ;-) – Chris May 04 '13 at 15:04
15

Tejas's answer is correct. To more specifically address some of your points:

Why does the following code not result in compile error?

The question is not answerable; it does not produce an error because it is legal code, but that's a tautology.

If your question is actually "which section of the C# specification makes this legal?", then that's an answerable question. The section on lifted equality operators makes it legal.

It's comparing a reference type to primitive type.

It is not. First off, avoid the term "primitive type"; the specification does not clearly define it and it is not a useful concept in C#. You meant to say I think that it is comparing a value of reference type to a value of value type.

Second, that's not correct either. The null literal is not of reference type or value type; it is of no type. It is convertible to any nullable value type or any reference type, but it is of no type just by itself.

In this case the null literal is converted to the nullable bool type.

Both null and false have to be interpreted into something for the compiler to do comparison.

Correct. They are interpreted as nullable bools.

is the parser simply scanning for such pattern and replace it with false?

No, but that's an excellent guess. The compiler would constant-fold, say, true == false down to false, but it does not do folding optimizations that involve nullable value types. The language could be redesigned to support constant folding on operations with nullable value type operands; had nullable value types counterfactually been in version one, the proposed feature likely would have been supported.

Vishal Suthar
  • 17,013
  • 3
  • 59
  • 105
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
12

Section 7.10.6 of the language specification (Reference type equality operators) states:

The x == null construct is permitted even though T could represent a value type, and the result is simply defined to be false when T is a value type.

This provision requires that null == false be false, and not a compiler error.

drf
  • 8,461
  • 32
  • 50