Before compilation and running, please read in the code comments or in chapter "Using the code" below how to install necessary libraries.
Introduction
Standard boolean type in programming languages has only two states “true
” and “false
”. For some cases, it is not enough. This article briefly describes development and practical use of ternary (three state) boolean type implemented in SSTypesLT
library.
Motivation
Ternary logic is a logic having third value named for example “Undefined
” or “Unknown
” additionally to “True
” and “False
”. Modern programming languages directly supports only two state (binary) boolean logic. This fact is a result of hardware characteristics, because hardware operates on base of binary system. But ternary logic can be very helpful for programmers in some cases.
Database Management Systems support NULL
values for all the data types representing absence of data. This value has the same semantic as logical “Unknown
” – absent data or unknown value. The author faced the same problem with configuration files, where getting information about absent value for a boolean key cannot be easy signalled. Actually ternary logic extends possibilities of other data processing techniques. Comparing of two double
values, for example, could be implemented with ternary logic with “Unknown
” result if one of the values is NAN
.
SSTypesLT Library
This article describes type SmartBool
located in SSTypesLT
library that is planned to be intensively used in data processing and quality control in project www.GoMap.Az. The author hopes to have time to develop SSTypesLT
library and describe it. The author heartily invites readers to try SSTypesLT
library and give their feedback.
SSTypesLT
library is an Open Source project located here. SSTypesLT
library is an open part of proprietary SSTypes
library intensively used in project www.GoMap.Az. The author acknowledges:
Nullable Boolean Types in C#
Nullable Boolean type can be used to implement ternary logic in C#. Semantically, “null
” value of Nullable Boolean variables fully equals to the NULL
value in databases. But it does not originate to support third logical state because it is provided by generics that is applicable for any value type. Nullable Boolean is adoption of this language feature to implementation of the ternary logic.
As a result, this approach has some drawbacks:
- “
null
” value has another semantics and behavior comparing to “true
” and “false
” - The operation with Nullable Boolean variable can throw an exception if the value is “
null
”. Operations with “true
” and “false
” in their turn do not ever throw exception. - Nullable Boolean variable in some operations, such as use in conditional statements requires explicit conversion to bool type
- Nullable Boolean variable takes additional memory space for storing “
hasValue
” flag (see struct Nullable <T>, Microsoft Reference Source)
Examples of such drawbacks are presented in the following code snippets:
bool? bn = null;
bool b2 = (bool)bn;
This code shows the following drawbacks:
- Assignment of value of variable
bn
to variable b2
throws an exception - Assignment of value of variable
bn
to variable b2
requires explicit conversion to bool
type (this cannot be considered as a flaw because Nullable Bool is more informative than bool
) - “
null
” value, but not an “unknown
” nor “Undefined
” assigned to variable bn (semantics problem)
bool? bn = null;
if ((bool)bn)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False or Unknown");
}
This code shows the following drawbacks:
- Statement “
if
” throws an exception - Statement “
if
” requires explicit conversion to bool
type String
"False or Unknown" will be never displayed if bn
is null
(semantics problem) - “
null
” value, but not an “unknown
” nor “undefined
” assigned to variable bn
(semantics problem)
Operators "&&" and "||"
Nullable Bool does not implement operators "&&
" and "||
". The following code will not be compiled because operator "&&
" cannot be apply to Nullable Bools:
bool? nb1 = null;
bool? nb2 = true;
bool? nbt1 = nb1 && nb2;
bool? nbt2 = nb1 & nb2;
Extension for Nullable Boolean Type
Extension for Nullable Boolean type could improve the readability of code, its semantics and behavior (see Ternary logic.). But it does not resolve all problems relating to adoption of Nullable Boolean type to implement ternary logic.
SmartBool Type in C#
SmartBool
is a structure, located in SSTypeLT
library (see SSTypes project.). The structure has features allowing to implement ternary logic in the most convenient for the programmer way. Another structure SmartInt
that represents 32-byte integer has been developed with the similar approach and successfully exploited for several years in web portal www.GoMap.Az, (see Accelerated .NET Types.).
SmartBool
is based on sbyte
(signed byte) type. This approach allows to implement negate operator “!
” without jump statements (“if
” statements). Jumps reduce predictability in CPU conveyor that influence performance. Unfortunately almost all operations of ternary logic cannot be implemented by single instructions on binary hardware platform. SmartBool
has been developed to be memory small and fast in “if
” statements. Performance of SmartBool
and Nullable Boolean has been benchmarked and compared (See chapter “Performance” below).
Behavior of SmartBool
slightly differs from behavior of Nullable Boolean. The following code is logically similar to the code presented above, but behaves in other manner.
SmartBool sb = SmartBool.Unknown;
bool sb2 = (bool)sb;
if (sb)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False or Unknown");
}
The advantages of the code are:
- Variable
sb
takes value of SmartBool.Unknown
that semantically is logical value, but not a representation of absent value; - Assignment of
sb
value to sb2
does not throw an exception; - Statement “
if
” works semantically right and does not throw an exception.
Implicit type cast in 2nd line needs because SmartBool
is more informative than bool
;
Operators “true“ and “false“
C# Reference by Microsoft describes “true
” and “false
” operators (see true and false operators (C# Reference).) as stated below. A type with the defined true operator can be the type of a result of a controlling conditional expression in the “if
”, “do
”, “while
”, and “for
” statements and in the conditional operator “?:
”.
The “true
” operator returns the bool value true
to indicate that an operand is definitely true. The “false
” operator returns the bool value true
to indicate that an operand is definitely false
. The “true
” and “false
” operators are not guaranteed to complement each other. That is, both the “true
” and “false
” operator might return the bool value false
for the same operand.
SmartBool
type implements “true
” and “false
” operators according to this description. It means that the following code will run as is described in comments:
SmartBool sb1 = ...
SmartBool sb2 = ...
...
if (sb1)
{
Console.WriteLine("True");
}
else
{
Console.WriteLine("False or Unknown");
}
if (!sb2)
{
Console.WriteLine("False");
}
else
{
Console.WriteLine("True or Unknown");
}
So, the “else
” section will run for Unknown value for both the above mentioned cases.
Operators "&&" and "||"
SmartBool
implements operators "&&
" and "||
". The following code will be compiled without problems:
SmartBool sb1 = null;
SmartBool sb2 = true;
SmartBool sbt1 = sb1 && sb2;
SmartBool sbt2 = sb1 & sb2;
Equality Operators “==” and “!=”
Equality operators “==
” and “!=
” of SmartBool
return result of type SmartBool
. These operators for bool
and Nullable Bool
return result as bool
value. This is important difference of SmartBool
from bool
and Nullable Bool
.
Semantic of comparing of unknown value with known one can be described as the process with unknown result. For long calculations, unknown value in input should produce unknown result if the result is dependent on this input value. SmartBool
supports this semantics, but Nullable Bool does not.
The following code showed this difference:
bool? nb1 = null;
bool? nb2 = true;
bool? nbt1x = nb1 == nb2;
SmartBool sb1 = null;
SmartBool sb2 = true;
SmartBool sbt1x = sb1 == sb2;
Truth Tables for SmartBool
SmartBool
supports standard truth tables for ternary logic. Truth tables for ternary logic are presented in many sources.
Operation NOT (operator “!
”)
Operation OR (operators “|
” and “||
”)
Operation AND (operators “&
” and “&&
”)
Operation EQUIVALENCE (operator “==
”)
Operation IMPLICATION
Operation EXCLUSIVE OR (operator “^
”)
Performance
Benchmarks shows that performance of SmartBool
is better than of Nullable Bool for operators “!
”, “true
”, and “false
”. Benchmarks of operators OR “|
” and AND “&
” for SmartBool
show somewhat slow performance comparing to Nullable Bool.
Equality operators of SmartBool
do not show good performance comparing to Nullable Bool. But this fact is the result that equality operators of SmartBool
implement a slightly complex logic and return SmartBool
. But equality operators of Nullable Bool
return bool
. See chapter "SmartBool
type in C# / Equality operators “==
” and “!=
”" above.
The following table shows benchmarks for several operations for considering 3 types. The values are relative and state only for comparing. Values for operators “true
” and “false
” are multiplied by 1000
. The table has been built on figures of table located below:
Benchmarks for assignment operators are presented in the following table. As it shows assignment of bool
to SmartBool
shows quite low performance. It is due to several “if
” - checks in the logic of operator. At the same time, assignment of SmartBool
to SmartBool
is somewhat faster than Nullable Bool
to Nullable Bool
.
The original benchmark output table. See the codes in downloadable zip-archives available by links in chapter "Using the code" below:
Method | Median | StdDev |
----------------------------- |------------ |------------ |
Asg_Bool2NullableBool | 32.1589 us | 14.2492 us |
Asg_Bool2SmartBool | 137.1827 us | 64.1514 us |
Asg_Bool2Bool | 23.0328 us | 9.5130 us |
Asg_NullableBool2NullableBool | 39.7319 us | 15.7200 us |
Asg_SmartBool2SmartBool | 28.5209 us | 11.4954 us |
NOT_Bool2Bool | 31.4698 us | 8.9368 us |
NOT_NullableBool2NullableBool | 111.9670 us | 38.0665 us |
NOT_SmartBool2SmartBool | 28.3513 us | 9.2716 us |
OR_Bool2Bool | 38.7323 us | 17.7660 us |
OR_NullableBool2NullableBool | 204.6962 us | 76.5525 us |
OR_SmartBool2SmartBool | 254.5754 us | 102.0478 us |
AND_Bool2Bool | 37.4744 us | 11.4081 us |
AND_NullableBool2NullableBool | 170.3016 us | 54.8486 us |
AND_SmartBool2SmartBool | 194.5647 us | 60.3215 us |
EQ_Bool2Bool | 35.4095 us | 12.3996 us |
EQ_NullableBool2NullableBool | 72.4243 us | 22.2527 us |
EQ_SmartBool2SmartBool | 184.6553 us | 56.8425 us |
NEQ_Bool2Bool | 37.7590 us | 12.0692 us |
NEQ_NullableBool2NullableBool | 70.6348 us | 21.5845 us |
NEQ_SmartBool2SmartBool | 154.4584 us | 62.6584 us |
TRUE_Bool | 317.5711 ns | 82.5786 ns |
TRUE_NullableBool | 425.9031 ns | 140.4248 ns |
TRUE_SmartBool | 299.9301 ns | 99.3415 ns |
FALSE_Bool | 312.6404 ns | 102.9978 ns |
FALSE_NullableBool | 494.9714 ns | 133.1724 ns |
FALSE_SmartBool | 294.6255 ns | 67.9278 ns |
Testing environment:
BenchmarkDotNet =v0.9.7.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-3610QM CPU 2.30GHz, ProcessorCount=8
Note: Due to cooling problem, the frequency of the CPU was forcibly set to 1.2 GHz.
Summary
To be laconic, the following results can be stated as summary:
- Nullable
Bool
(bool?
) was not designed to implement ternary logic - Extension for Nullable
Bool
can improve Nullable Bool
but not solve all problems SmartBool
implements ternary logic by the best way - Logic of
SmartBool
differs from logic of Nullable Bool
Codes contain examples and benchmark. Microsoft Visual Studio Community 2015 was used to create the projects. Both projects require installation of SSTypesLT
library. SmartBoolBenchMark
project requires also BenchmarkDotNet
library.
To install the libraries, you can use NuGet Package Manager Console from Microsoft Visual Studio. NuGet Package Manager Console can be activated through user menu "Tools/NuGet Package Manager/Package Manager Console".
For installation of SSTypesLT
library, type the following command and press Enter:
Install-Package SSTypesLT
For installation of BenchmarkDotNet
library, type the following command and press Enter:
Install-Package BenchmarkDotNet
For .NET Framework version 4.0 or later, you can use version 0.9.7 installed by the following command:
Install-Package BenchmarkDotNet -Version 0.9.7
The code can be downloaded from the link at the top of this page.
History
- 20th April, 2019 - Initial article released