0

How should one read

!nullableboolean ?? false 

when nullableboolean == null it equals false.

According to:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/

! binds stronger than ??

It also differs from

!(nullableboolean ?? false)

when nullableboolean == null it equals true.

But then !nullableboolean == null this seems undocumented. And of course !null doesn't compile. Maybe it only works in conjunction with ??. So maybe ?? has an undocumented counterpart-operator ! ??, but !null ?? false doesn't compile either.

Does anybody know of some explanation or documentation?

Wouter
  • 2,540
  • 19
  • 31

2 Answers2

7

Using the ! operator on a null boolean? will produce null. Documentation:

The predefined unary and binary operators and any user-defined operators that exist for value types may also be used by nullable types. These operators produce a null value if the operands are null; otherwise, the operator uses the contained value to calculate the result.

Ry-
  • 218,210
  • 55
  • 464
  • 476
6

Ryan's answer is correct; to address your many other questions:

How should one read !nullableboolean ?? false

This is the same as (!nullableboolean) ?? false which is the same as bool? temp = !nullableboolean ... temp.HasValue ? temp.Value : false

It also differs from !(nullableboolean ?? false)

Correct. That would have the semantics of !(nullableboolean.HasValue ? nullableboolean.Value : false)

But then !nullableboolean == null

If nullableboolean is null then its inverse is also null, correct. The opposite of "I don't know if this is true or false" is "I don't know if this is false or true". You still don't know.

this seems undocumented.

It is not.

And of course !null doesn't compile.

I do not recall the reason for this or where in the Roslyn code it is determined. Overload resolution could deduce that there are no applicable user-defined operators -- because they are looked up by type, and null has no type -- and that the sole built-in operator is the lifted ! operator.

But a good reason for this exception to the normal rules would be that it's almost always a mistake! If "a null bool?" was intended then (bool?)null or default(bool?) or new bool?() would all be preferable. If it wasn't intended, then the code is wrong. Either way, it can be safely rejected.

If I have a free moment I'll take a look through the code and see if I can recall where this check got implemented.

Maybe it only works in conjunction with ??

No.

So maybe ?? has an undocumented counterpart-operator ! ??

No.

!null ?? false doesn't compile either.

Correct; again !null is rejected by some special rule.

Does anybody know of some explanation or documentation?

Read the specification. My articles on how I wrote the nullable arithmetic optimizer might also be of interest to you:

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

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thnx, I guess I was looking in the wrong corner. It's the operator that is overloaded for the nullable boolean. About `!null` not compiling. Could it be related to: `bool b = true; bool? nb = b ? b : null;` not compiling? in both cases it seems obvious that `null` needs to be `(bool?)null` and casting it solves the problem. – Wouter Jan 17 '18 at 23:13
  • @Wouter: That's a plausible guess, but incorrect. You're right that the two problems have the same solution, but they are different problems. The rule about the consequence and alternative of the conditional operator having a specific consistent type is not involved in the unary operator overload resolution process. – Eric Lippert Jan 17 '18 at 23:25
  • For future reference this answer explains the rull https://stackoverflow.com/a/2608930/4491768 – Wouter Jan 19 '18 at 11:58