The C# difference 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 operation x & y, except that y is evaluated only if x is true.
  • The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is false.

The later versions (starting with version 3) state:

  • The operation x && y correspond to the operation x & y, except that y is evaluated only if x is not false.
  • The operation x || y correspond to the operation x | y, except that y is evaluated only if x 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 as T.false(x) ? x : T.&(x,y), …... In other words, x is first evaluated and operator false is invoked on the result to determine if x is definitely false. Then, if x is definitely false, the result of the operation is the value previously computed for x. Otherwise, y is evaluated, and the selected operator & is invoked on the value previously computed for x and the value computed for y to produce the result of the operation.
  • The operation x || y is evaluated as T.true(x) ? x : T.|(x,y), …... In other words, x is first evaluated and operator true is invoked on the result to determine if x is definitely true. Then, if x is definitely true, the result of the operation is the value previously computed for x. Otherwise, y is evaluated, and the selected operator | is invoked on the value previously computed for x and the value computed for y 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 returns false and operator false returns false. 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.

Tags: C#
Created: 7/26/2016 7:43:06 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.