library of assembled shared sources |
http://lass.cocamware.com |
#include <tri_bool.h>
Public Types | |
enum | State { sFalse, sTrue, sUnknown } |
Public Member Functions | |
TriBool (State iState=sUnknown) | |
TriBool (bool iBool) | |
const State | state () const |
State & | state () |
TriBool | operator! () const |
operator SafeBool () const | |
bool | isTrue () const |
bool | isFalse () const |
bool | isUnknown () const |
Private Attributes | |
State | state_ |
Related Functions | |
(Note that these are not member functions.) | |
const TriBool | unknown (TriBool::sUnknown) |
constant to be used as new keyword like true and false |
Inspired by Boost three-state boolean logic library 'boosttribool' by Doug Gregor (gregod@cs.rpi.edu).
Booleans are great to express binary states, to express if something is true or false. But they lack the concept of Not-A-Number (NaN
). Indeed, with traditional booleans, there's no way to express that you don't know, that the boolean value is invalid. That's when this TriBool comes into action. TriBool adds one extra state to the traditional true
and false:
unknown
. As said, this unknown
acts like the NaN
for floating point values and behaves much the same way (though not entirely the same!).
unknown
can not come into existance as long as all your operands are in a known state (true
or false
). You have to inject an unknown
value yourself, and this section merely describes how it will flow through your code.
rule: In TriBool unary expressions, if the argument is unknown
, then the result will yield unknown
too..
Check out operator!
Indeed, if a
is unknown
, then !a
is unknown
too.
rule: In TriBool binary expressions, if at least one of the operands is unknown
, then the result yields unknown
, except if one of the operands is known (true
or false
) and provides enough information to result in a known state.
The first part is obvious. In an expression a
==
b
, if one of the operands is unknown
, we can not possible know if a
and b
are equal or not. It will yield unknown
. However, there are two situations in which a binary expression with an unknown operands still results in a known state. These are:
false
&&
unknown
yields false
. Indeed, for an AND operation to yield true
, both operands must be true
. Since we know at least one of them is false
, we can know for sure the result is false
too.true
||
unknown
yields true
. Indeed, for an OR operation to yield true
, at least one of the operands must be true
. Since we know the left operand is true
we know for sure we have at least one operand that is true, hence the result is true
.
Since AND and OR are commutative, this is also valid for unknown
&&
false
and unknown
||
true
. In all other cases, a binary expression with at least one unknown
operand will yield unknown
.
unknown
behaves much like NaN
, but that's not really true. If you compare two operands that are NaN
, you'll get false
as result (a known state), where as if both operands are unknown
, it will not result false
but unknown!
in contrary to traditional boolean logic, a!=b
||
a==b
does not always yield true!
It will be unknown
if one of the operands is unknown.
if/else
statements (and for
and while
loops ...). For instance, the following examples are not equivalent (as they would be for plain old boolean logic). Notice what happens if a
is unknown!
TriBool a; if (a) { foo(); // called if a is true. } else { bar(); // called if a is false OR unknown. } if (!a) { bar(); // called if a is false } else { foo(); // called if a is true OR unknown. }
The discrepancy is due to the fact there isn't an unambigious way to reduce the three states of a TriBool to the two states of the if/else
statement, or the traditional boolean logic. In the former, the if
block tests if a
is true
and the else
block gets the other two states. In the latter, the if
block tests if a
is false
and again the else
block gets the other two states. So, in any case, if a
is unknown, you'll end up in the else
block.
bool
. That's because of the ambigious mapping from TriBool to bool
as described above. But then how does if
(a) works? If does need a boolean value, doesn't it? The trick is in the operator
SafeBool()
. It will return a non-NULL pointer if and only if the TriBool is true
, what invokes the if
block. If the TriBool is false
or unknown
, then a NULL pointer is returned instead and the else
block is called.if/else
construction, your code will typically look like the following:
if (a) { foo(); // called if a is true } else if (!a) { bar(); // called if a is false } else { fun(); // called if a is unknown }
This is equivalent to:
switch (a.state()) { case TriBool::sTrue: foo(); break; case TriBool::sFalse: bar(); break; default: LASS_ASSERT(a.state() == TriBool::sUnknown); fun(); break; }
a
is in a unknown state by comparing it to the constant unknown
. You might expect it to yield true
if a
is indeed, unknown, but it will always return unknown
instead. After all, it cannot know if both sides are equal, since at least one is unknown (unknown
itself). To test if a
TriBool is indeed unknown, you have to use the method TriBool::isUnknown()
.TriBool a; if (a == unknown) { // BAD! unreachable code, the test will never yield true. } if (a.isUnknown()) { // GOOD! this code will be reached if the state of a is unknown. }
Definition at line 207 of file tri_bool.h.
lass::num::TriBool::TriBool | ( | State | iState = sUnknown |
) |
lass::num::TriBool::TriBool | ( | bool | iBool | ) |
const State lass::num::TriBool::state | ( | ) | const |
State& lass::num::TriBool::state | ( | ) |
TriBool lass::num::TriBool::operator! | ( | ) | const |
lass::num::TriBool::operator SafeBool | ( | ) | const |
bool lass::num::TriBool::isTrue | ( | ) | const |
bool lass::num::TriBool::isFalse | ( | ) | const |
bool lass::num::TriBool::isUnknown | ( | ) | const |
const TriBool unknown | ( | TriBool::sUnknown | ) | [related] |
constant to be used as new keyword like true
and false
State lass::num::TriBool::state_ [private] |
Definition at line 233 of file tri_bool.h.
Generated on Mon Nov 10 14:22:10 2008 for Library of Assembled Shared Sources by 1.5.7.1 |