Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong compiler warning when comparing struct to null

Consider the following code:

DateTime t = DateTime.Today;

bool isGreater = t > null;

With Visual Studio 2010 (C# 4, .NET 4.0), I get the following warning:

warning CS0458: The result of the expression is always 'null' of type 'bool?'

This is incorrect; the result is always false (of type bool):

Now, the struct DateTime overloads the > (greater than) operator. Any non-nullable struct (like DateTime) is implicitly convertible to the corresponding Nullable<> type. The above expression is exactly equivalent to

bool isGreater = (DateTime?)t > (DateTime?)null;

which also generates the same wrong warning. Here the > operator is the lifted operator. This works by returning false if HasValue of any of its two operands is false. Otherwise, the lifted operator would proceed to unwrap the two operands to the underlying struct, and then call the overload of > defined by that struct (but this is not necessary in this case where one operand does not HasValue).

Can you reproduce this bug, and is this bug well-known? Have I misunderstood something?

This is the same for all struct types (not simple types like int, and not enum types) which overload the operator in question.

(Now if we use == instead of >, everything ought to be entirely similar (because DateTime also overloads the == operator). But it's not similar. If I say

DateTime t = DateTime.Today;

bool isEqual = t == null;

I get no warning ☹ Sometimes you see people accidentally check a variable or parameter for null, not realizing that the type of their variable is a struct (which overloads == and which is not a simple type like int). It would be better if they got a warning.)


Update: With the C# 6.0 compiler (based on Roslyn) of Visual Studio 2015, the incorrect message with isGreater above is changed into a CS0464 with a correct and helpful warning message. Also, the lack of warning with isEqual above is fixed in VS2015's compiler, but only if you compile with /features:strict.

like image 236
Jeppe Stig Nielsen Avatar asked Oct 24 '12 09:10

Jeppe Stig Nielsen


3 Answers

I discovered this error independently while implementing lifted operator behaviour in Roslyn, and I fixed it in Roslyn before I left.

Sorry that I didn't see this when you posted it back in October. Thanks for submitting it to Connect! And many apologies for the error; it is a long-standing error in operator semantic analysis.

Incidentally, I'll be discussing how Roslyn optimizes lifted expressions on http://ericlippert.com later this month (December 2012), so if this subject interests you, check it out:

http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/

like image 194
Eric Lippert Avatar answered Nov 06 '22 03:11

Eric Lippert


You are correct: this is a bug in Visual Studio. The C# 4.0 standard (§ 7.3.7 Lifted operators) has this to say:

For the relational operators

<  >  <=  >=

[…] The lifted operator produces the value false if one or both operands are null.

And in fact, in MonoDevelop, you get the following warning instead:

The result of comparing type System.DateTime with null is always false.

like image 5
Konrad Rudolph Avatar answered Nov 06 '22 02:11

Konrad Rudolph


DateTime t = DateTime.Today;

bool isGreater = (DateTime?)t > (DateTime?)null;

In this scenario what the warning is about is the t > null. That is never going to be true. Because It can't be evaluated.

In this scenario:

bool isGreater = (DateTime?)t > (DateTime?)null;

We are evaluating (DateTime?)t > (DateTime?)null;

Or essentially in the best case scenario t > null; same as before. DateTime.Now can never be greater than Undefined, hence the warning.

like image 1
awright18 Avatar answered Nov 06 '22 01:11

awright18