10

There is a lot of syntax sugar with Nullable<T> like those:

int? parsed to Nullable<int>

int? x = null
   if (x != null) // Parsed to if (x.HasValue)

x = 56; // Parsed to x.Value = 56;

And more.

Why if condition with Nullable doesn't work?

if (x)
{} 

It gets Complier error saying can't convert Nullable<bool> to bool.
Why it's not being parsed to if (x.HasValue && x.Value == true) or something similar?

It's the most obvious usage for Nullable<bool>

gdoron
  • 147,333
  • 58
  • 291
  • 367
  • Well, I assume because the generic argument is a special case, why should it be treated differently than Nullable? – Tomislav Markovski Jan 18 '12 at 14:27
  • 5
    I may be overly pedantic but it's worth noting that `x = 56;` is not parsed to `x.Value = 56;` as the struct is immutable and `.Value` is read-only. It's more of `x = new Nullable(56);` – Anthony Pegram Jan 18 '12 at 15:01
  • @AnthonyPegram. Maybe overly pedantic, but very informative as well **+1** – gdoron Jan 18 '12 at 15:05
  • I would suggest that if you were going to use something with an `if` statement, it should "obviously" be a `bool`. There are other things you can use with `if` (override `true`) but seeing something "almost" boolean would suggest you want "almost" boolean behaviour but have a good reason for not just having a boolean, so "obviously" there's at least one way in which you don't want it to behave like a bool, why shouldn't that include use in an `if` statement? – Jon Hanna Jan 18 '12 at 15:20

10 Answers10

26

It's the most obvious usage for Nullable<bool>

Your "obvious" behaviour leads to many inobvious behaviours.

If

if(x)

is treated as false when x is null, then what should happen to

if(!x)

? !x is also null when x is null, and therefore will be treated as false also! Does it not seem strange that you cannot reverse the behaviour of a conditional with an inversion?

What about

if (x | !x)

Surely that should always be true, but if x is null then the whole expression is null, and therefore false.

It is better to avoid these inobvious situations by simply making them all illegal. C# is a "make the user say what they mean unambiguously" language.

I believe that VB has the behaviour you want. You might consider switching to VB if this is the sort of thing you like.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Which still leaves to the related question of why `if` only requires `op_true` instead of an implicit conversion to bool. `op_true`/`op_false` seem to be designed to work with shortcuiting operators, but it doesn't seem natural than any type that supports short-circuiting should also support `if`. – CodesInChaos Jan 18 '12 at 15:31
  • @CodeInChaos: It seems *unnatural* to you that if `if(x&&y) Z()` is legal then `if(x) if (y) Z()` is also legal? I think of those two as being "the same thing", so it seems very intuitive to me that if one is legal, the other ought to be also. – Eric Lippert Jan 18 '12 at 16:39
  • I just read your [blog post](http://blogs.msdn.com/b/ericlippert/archive/2012/03/26/null-is-not-false.aspx) on the very same subject from one month ago. Maybe it will a good idea to add it to your answer? I don't want to edit `Eric Lippert` answer myself... – gdoron May 03 '12 at 11:06
  • This answer seems outdated, because this statement compiles fine in C#7 VS 2017: 'if (files[0]?.ContentLength > 0) { }'. It seems obvious to me that if you're checking for the affirmative condition that some content length is greater than zero, then the statement can't possibly be true if the content doesn't even exist. For example, I could say "if Fred has more than 20 dollars in his bank account, then...." and consider that false if Fred doesn't even have a bank account. – Triynko Sep 18 '17 at 19:44
  • @Triynko: I'm not following your train of thought here. If your point is that "lifted" operations involving nullable comparison operators are logically inconsistent then that has nothing to do with C# 7; that's been true since C# 2.0. I discussed this on my blog ten years ago: https://blogs.msdn.microsoft.com/ericlippert/2007/06/27/what-exactly-does-lifted-mean/, and two years ago here https://ericlippert.com/2015/08/31/nullable-comparisons-are-weird/ – Eric Lippert Sep 18 '17 at 19:49
  • I disagree with your statement "!x is also null when x is null" The opposite of null would be something. That would be the logical result. If (!null) would return true, but you wouldnt be able to use !null by itself. Its not implemented like that, but why would that be inobvious behaviour? – Tigerware Oct 16 '18 at 08:35
  • 3
    @BluE: You are free to disagree with my statement but it is a correct description of the rules of C#. If you believe that the rules of C# are badly designed, well, you're free to have that opinion; try designing your own language that has rules that you like! – Eric Lippert Oct 16 '18 at 16:44
15

Simply put, it fails to compile because the specification says it should - an if condition requires a boolean-expression - and an expression of type Nullable<bool> isn't a boolean-expression:

A boolean-expression is an expression that yields a result of type bool; either directly or through application of operator true in certain contexts as specified in the following.

However, it's easy to work round:

if (x.GetValueOrDefault())
{
}

Or to possibly be clearer:

if (x ?? false)
{
}

The latter approach is useful as it means you can easily change the behaviour if x is null, just by changing it to x ?? true.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

It's not that obvious that null should mean false. A null value means that the value is unknown or uninitialized. It's unknown whether the value is true or false. Who said null should behave like false?

A more obvious usage for Nullable<bool> is to store something that can be either true or false, but sometimes is irrelevant or unknown, in which case the value is null.

Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
  • This statement compiles fine in C#7 VS 2017: 'if (files[0]?.ContentLength > 0) { }'. In this case, a null value is treated as false. It seems obvious to me that if you're checking for the affirmative condition that some content length is greater than zero, then the statement can't possibly be true if the content doesn't even exist. For example, I could say "if Fred has more than 20 dollars in his bank account, then...." and consider that false if Fred doesn't even have a bank account. – Triynko Sep 18 '17 at 19:48
3

I think that wouldn't be a good idea. That null evaluates to false doesn't feel natural. Especially in if+else statements. So forcing the user to be explicit with: if(nb==true) and if(nb==false) is a good idea IMO.

MSDN says:

bool? b = null;
if (b) // Error CS0266.
{
}

This is not allowed because it is unclear what null means in the context of a conditional. To use a bool? in a conditional statement, first check its HasValue property to ensure that its value is not null, and then cast it to bool. For more information, see bool. If you perform the cast on a bool? with a value of null, a InvalidOperationException will be thrown in the conditional test.

http://msdn.microsoft.com/en-us/library/bb384091.aspx

Some of the answers to my question Why are there no lifted short-circuiting operators on `bool?`? touch on these aspects too

Community
  • 1
  • 1
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
2

Technically it doesn't work because Nullable<T> does not define a conversion operator to bool.

Practically it is not supported for a variety of reasons, including:

  • There are no implicit conversions to bool anywhere in C# -- why should there be in Nullable<T>?
  • Any conversion available would have to be declared for every T in Nullable<T> -- how is that possible when you can plug in your own type as T that the compiler knows nothing about?
  • What would be the semantics of if(!x)?
Jon
  • 428,835
  • 81
  • 738
  • 806
2

It's the most obvious usage for Nullable

Be careful with statements like that. What seem obvious to you isn't necessarily what is obvious for some one else.

Furthermore,

if(x) {}

would also be illegal in case x was a reference type, so in the interest of consistency, the behavior should be the same for Nullables.

Rik
  • 28,507
  • 14
  • 48
  • 67
  • `if (x) {}` is not per se illegal on reference types. For example, reference types that implement `op_true` can be used in an if statement. See Jon Skeet's answer for the quote from the spec: http://stackoverflow.com/a/8911755/385844. – phoog Jan 18 '12 at 18:43
  • I wouldn't say it's a special case. It is true of all types without regard to their being value or reference types. String and int are equally unsuitable for the condition of an if statement. – phoog Jan 20 '12 at 02:20
1

Anything between the parentheses from the if-statement must evaluate to true or false. A nullable bool can evaluate to null, true or false.

Mithrandir
  • 24,869
  • 6
  • 50
  • 66
1

You can't do

if (x)
{...}

for the exact same reason you cannot write

int? a = null;
var b = a + 1;

A nullable boolean is not a boolean. In some cases, you want to consider a null bool? as true, and sometimes you want to consider it false. The language design does not make that decision for you.

Falanwe
  • 4,636
  • 22
  • 37
1

Consider what whould happen in this case then

bool? nullBool = null;
if (nullBool)
{
    someCode();
}

It would be impossible to tell if it entered the if senctence because the bool was null or false. That is probably not desirable

rasmusvhansen
  • 1,452
  • 1
  • 12
  • 13
1

It's because a nullable bool cannot be implicitly converted to a bool. It's the same reason why you can do this :

int x1 = 7;
int? x2 = x1;

but you can't do this :

int? x1 = 7;
int x2 = x1;

you have to check before if it contains a value. Implicitly converting with nullable types can only be done when assigning a value, not when using that value.