The C# Difference between "true" and "not false"






4.18/5 (6 votes)
This post discusses the difference in C# between true and not false.
This is the story of a C# language specification change.
The specification changed because the 1.0 version of the C# spec disagreed with itself, and one of those locations was incorrect and broke a feature.
The change is in the section on “Conditional Logic Operators”. Version 1 of the spec states:
- The operation
x && y
corresponds to the operationx & y
, except thaty
is evaluated only ifx
istrue
. - The operation
x || y
corresponds to the operationx | y
, except thaty
is evaluated only ifx
isfalse
.
The later versions (starting with version 3) state:
- The operation
x && y
correspond to the operationx & y
, except thaty
is evaluated only ifx
is not false. - The operation
x || y
correspond to the operationx | y
, except thaty
is evaluated only ifx
is not true.
Why the change?
Well, a couple sections later, the spec defines “User-Defined Conditional Logical Operators”. The C# Language does not allow you to create a user defined operator &&
or operator ||
. Instead, you must define operator |
, operator &
, operator true
and operator false
. Here is the pertinent text:
The &&
and ||
operation is evaluated by combining the user-defined operator true
or operator false
with the selected user-defined operator:
- The operation
x && y
is evaluated asT.false(x) ? x : T.&(x,y)
, …... In other words,x
is first evaluated and operatorfalse
is invoked on the result to determine ifx
is definitelyfalse
. Then, ifx
is definitelyfalse
, the result of the operation is the value previously computed forx
. Otherwise,y
is evaluated, and the selected operator&
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation. - The operation
x || y
is evaluated asT.true(x) ? x : T.|(x,y)
, …... In other words,x
is first evaluated and operatortrue
is invoked on the result to determine ifx
is definitelytrue
. Then, ifx
is definitelytrue
, the result of the operation is the value previously computed forx
. Otherwise,y
is evaluated, and the selected operator|
is invoked on the value previously computed forx
and the value computed fory
to produce the result of the operation.
The key points here are that for operator &&
, x
is checked to ensure that it is not false
, and for operator ||
, x
is checked to ensure that it is not true
.
Why the Spec Had to Change
The version 1.0 of the spec had serious limitations. User Defined Types that defined operator &
or operator |
would work with if and only if operator true
and operator false
were defined such that exactly one of them was true
at all times.
Nothing in the language mandates that explicitly.
As a thought exercise, suppose you have a type that may be neither true
nor false
in some states. Maybe there are ranges of “true
” and “false
” and a range in between of “neither true nor false”.
If you want a concrete example, consider a type that has a single byte field. Its operator true
returns true
when all bits are 1
. Its operator false
returns true
when all bits are 0
. In all cases, to evaluate ‘x && y
’, or ‘x || y
’ requires both the left and right side of the operator. No short circuiting is possible.
That’s why the spec changed at version 3.
A Little More Explanation in the Spec
We felt the spec needed a little more explanation around this change. In ECMA version 5, we’re adding this note:
Note: The reason that short circuiting uses the 'not true' and 'not false' conditions is to enable user defined conditional operators to define when short circuiting applies. User defined types could be in a state where
operator true
returnsfalse
andoperator false
returnsfalse
. In those cases, neither&&
or||
would short circuit.
The C# spec (thankfully) has relatively few locations where the spec disagrees with itself. But in a large document, it’s easy for them to creep in. Several people review and make corrections whenever we find them.