Software Testing Blog

Warnings vs errors

Today on Ask the Bug Guys, reader Raghavendra has a question about this bug:

    if (someValue != null)
    {
        ...

if someValue is of a non-nullable value type that defines an equality operator — like, int or Guid — then this code is legal, but almost certainly wrong, since the condition will always be true. Raghavendra’s question is why should the compiler give a warning here rather than an error?

Good question. Before getting into that though I want to clear up a few related points.

First off, let me say that some releases of the compiler fail to give a warning for some cases where a non-nullable value type is compared to null. This was an accident; it was a bug introduced in I believe C# 3. Apologies for the mistake.

Second, it might not be clear why this code is legal at all. Operators are analyzed using a process almost identical to method overload resolution; shouldn’t operator overload resolution be failing here? No; if there exists an equality operator T==T for non-nullable value type T then you get a “lifted” operator T?==T? for free, which has the semantics “true if both null, false if exactly one null, otherwise defer to the original operator”. Overload resolution is choosing the lifted operator here.

So now to come to the actual question. The code is clearly wrong. Shouldn’t clearly wrong code be an error, not a warning? Let’s look at some analogous situations.

  • Pro error: C# already makes many “impossible” uses of equality comparisons illegal. Comparison of a value type to a reference type, or comparison of unrelated reference types is illegal.
  • Pro warning: Similar expressions that always produce a given result are warnings, not errors, like null is string.
  • Pro neither: C# does not make illegal many other impossible equality comparisons. Comparing an integer to the double 12.3 can’t possibly be true either but that is neither a warning nor an error. (Though maybe it should be.) In general, determining whether a comparison is always true or always false is equivalent to the halting problem, so we can’t always produce a warning or error.

We don’t seem to have learned much there. Some other impossible comparisons are errors, some are warnings. What are some other points for and against making such a comparison an error?

  • Pro error: This was an error in C# 1.0, before nullable value types were added to the language. Existing code would not have been broken by keeping it an error in C# 2.0.
  • Pro warning: making expressions that always produce the same value into errors rather than warnings increases the difficulty of making computer-generated code correct. Sometimes it is convenient for an automatic code generator to generate redundant code.
  • Pro warning: consistency with generics.

That last one needs some explanation. Suppose we have:

void M<T>(T t)
{
  if(t == null) ...

Clearly what is best is if M<int> has the same semantics as

void M_int(int t)
{
  if(t == null) ...

So then the question is: suppose the latter is an error. Should the former be an error as well, provided that T is not constrained to be a reference type?

The language designers decided that this should be legal; if under construction T is a type that cannot be compared to null then the comparison to null is false, not an error. For consistency then it seems reasonable that the non-generic version of the same code should have the same behaviour.

Summing up: there are reasonable arguments on both sides, but on balance I think the decision to make this a warning rather than an error was the right one.


As always, if you have questions about a bug you’ve found in a C, C++, C# or Java program that you think would make a good episode of ATBG, please send your question along with a small reproducer of the problem to TheBugGuys@Coverity.com. We cannot promise to answer every question or solve every problem, but we’ll take a selection of the best questions that we can answer and address them on the dev testing blog every couple of weeks.

  1. I suspect the bolded word in the quote below ought to be “value”; you’ve had many discussions about the impracticality / undesirability of non-nullable reference types, at least in C#.

    Second, it might not be clear why this code is legal at all. Operators are analyzed using a process almost identical to method overload resolution; shouldn’t operator overload resolution be failing here? No; if there exists an equality operator T==T for non-nullable reference type T then you get a “lifted” operator T?==T? for free, which has the semantics “true if both null, false if exactly one null, otherwise defer to the original operator”.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Current day month ye@r *