1

I am confused with c# compiler in case of negating the null value of bool?. Compiler does interpret !null as null. My expectation is to raise

CS0266 (Cannot implicitly convert type 'bool?' to 'bool')

Sample code:

bool? nullableVal = null;

//if (nullableVal)  //OK: CS0266 bool? can't be converted to bool
//    ;
var expectCS0266 = !nullableVal;//No compiler error/warning

//if ((!null) ?? false)//OK: CS8310 Operator '!' cannot be applied to operands of type "<NULL>"
//    ;

if (! nullableVal ?? false)
    ;//this statement isn't reached, because of precedence of ! is higher than ??
    //and !null == null

if (!(nullableVal ?? false))
    ;//this statement is reached, OK

Can somebody prove why the compiler is right or vice versa.

Rekshino
  • 6,954
  • 2
  • 19
  • 44
  • 1
    Does [this answer](https://stackoverflow.com/a/9013171/43846) help? - _"Nullable is a very special type and its magical properties are embedded deeply within the C# language and the runtime"_ – stuartd Feb 12 '20 at 14:33
  • @stuartd the answer from canton7 seems to be shorter and clearer. – Rekshino Feb 12 '20 at 14:42

1 Answers1

6

See Section 7.3.7 of the spec:

Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:

  • For the unary operators
        + ++ - -- ! ~
    a lifted form of an operator exists if the operand and result types are both non-nullable value types. The lifted form is constructed by adding a single ? modifier to the operand and result types. The lifted operator produces a null value if the operand is null. Otherwise, the lifted operator unwraps the operand, applies the underlying operator, and wraps the result.

(Emphasis mine)

So:

bool? x = null;
bool? y = !x;

Follows this rule. We're using the lifted form of the unary ! operator, which results in null if the value it's applied to is null.

!null isn't allowed, because null isn't of type Nullable<T>. !(bool?)null works, however (although it produces a compiler warning).

! indeed has higher precedence than ??, see Section 7.3.1

canton7
  • 37,633
  • 3
  • 64
  • 77
  • 2
    I would mark it __"The lifted operator produces a null value if the operand is null"__ bold. Thank you for quote from spec! – Rekshino Feb 12 '20 at 14:48