Discussion:
C++ types std::boolean, std::true, std::false and std::bool_intermediate
Jim Smith
2013-06-24 08:37:47 UTC
Permalink
Hi,

I posted this once in more detail, but didn't see it listed.

I'm interested in an implementation of C++ types std::boolean, std::true,
std::false, and std::bool_intermediate for states that are not true or
false. These types would allow boolean results to be handled using OO
techniques instead of if/else statements. Also, std::bool_intermediate take
into account the superposition of the two boolean states.

An implementation of these types would allow the result of a boolean method
to be handled using multiple dispatch instead of traditional if/else
statements:

(multiple dispatch is explained in Scott Meyers "More Effective C++")

//usage example:

class handler_concept
{
public:
...
void operator()(const std::true<handler_concept>& bt) ;
void operator()(const std::false<handler_concept>& bf) ;
void operator()(const std::bool_intermediate<handler_concept>& bi) ;
...
};

handler_concept hc; // class object that handles boolean states
std::boolean<handler_concept> bln(hc); // creation of std::boolean object
that will invoke method on handler_concept object hc

SomeOperation s_op; // class object with boolean method
bln = s_op.some_bool_function(); // bln is assigned the boolean value
and invokes the method on handler_concept object hc

//end of example

I implemented these boolean types to try the purposed technique. It's more
elegant than if/else and allows each class to define its own meaning of
true or false etc., increasing encapsulation of an application's concepts.


Thanks & Regards,
--James Smith
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Jonathan Wakely
2013-06-24 10:25:21 UTC
Permalink
Post by Jim Smith
Hi,
I posted this once in more detail, but didn't see it listed.
I'm interested in an implementation of C++ types std::boolean, std::true,
std::false, and std::bool_intermediate for states that are not true or
false. These types would allow boolean results to be handled using OO
techniques instead of if/else statements.
Why is that a good thing?

I know that type dispatching with an open set of types is much better
handled with virtual functions than with if/else statements, but boolean is
not an open set, it has true and it has false.
Post by Jim Smith
Also, std::bool_intermediate take into account the superposition of the
two boolean states.
This seems to be confusing two concepts: compile-time booleans (which we
have with std::true_type and std::false_type) and a tri-bool type. Why
would we want an intermediate state for booleans? Does it model this code?

if (some_condition)
{ }
else if (!some_condition)
{ }
else /* ??? */
{ }

If we can't do it with booleans, why should we be able to do it with a type
representing booleans?
Post by Jim Smith
An implementation of these types would allow the result of a boolean
method to be handled using multiple dispatch instead of traditional if/else
(multiple dispatch is explained in Scott Meyers "More Effective C++")
class handler_concept
{
...
void operator()(const std::true<handler_concept>& bt) ;
void operator()(const std::false<handler_concept>& bf) ;
void operator()(const std::bool_intermediate<handler_concept>& bi) ;
...
};
handler_concept hc; // class object that handles boolean states
std::boolean<handler_concept> bln(hc); // creation of std::boolean
object that will invoke method on handler_concept object hc
SomeOperation s_op; // class object with boolean method
bln = s_op.some_bool_function(); // bln is assigned the boolean value
and invokes the method on handler_concept object hc
//end of example
I implemented these boolean types to try the purposed technique. It's more
elegant than if/else and allows each class to define its own meaning of
true or false etc., increasing encapsulation of an application's concepts.
How did you implement it when true and false are keywords?

What's so wrong with if/else that "OO techniques" are needed to replace
it? I don't consider your example elegant at all.

This might be useful in your own project, why should it be standardised?
What problem are you solving?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Greg Marr
2013-06-24 17:40:51 UTC
Permalink
std::bool_intermediate for states that are not true or false. ... Also,
std::bool_intermediate take into account the superposition of the two
boolean states.
This sounds exactly like std::optional<bool>.

If you really want OO behavior from a class here, I think this code would
be much clearer,
just derive from this dispatch class and implement the virtual functions.

class optional_bool_dispatch
{
public:
void operator()(std::optional<bool> const &res)
{
if(!res)
if_indeterminate();
else if(*res)
if_true();
else
if_false();
}

protected:
virtual void if_true() = 0;
virtual void if_false() = 0;
virtual void if_indeterminate() = 0;
};

SomeOperation s_op; // class object with std::optional<bool> method
optional_bool_dispatch_derived hc; // class derived from
optional_bool_dispatch
hc(s_op.some_bool_function());
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Martinho Fernandes
2013-06-26 16:11:12 UTC
Permalink
Post by Greg Marr
std::bool_intermediate for states that are not true or false. ... Also, std::bool_intermediate take into account the superposition of the two boolean states.
This sounds exactly like std::optional<bool>.
I think `optional<bool>` has confusing semantics to be used for
tri-value logic. I'll call the third value "third", just for
exposition. Consider:

// I would normally not use == true, but I think it is worth for clarity here
optional<bool> a = true;
assert(bool(a) == true);
assert(bool(!a) == false);
assert(*a == true);

optional<bool> b = false;
assert(bool(a) == true);
assert(bool(!a) == false);
assert(*a == false);

auto third = none;
optional<bool> c = third;
assert(bool(c) == false);
assert(bool(!c) == true);
// *c is UB

With this `bool(a)` or any contextual conversion to bool, like
`if(a)`, means "Is `a` not the third value?"/
`bool(!a)` means "Is `a` the third value?"
And `*a` means "assuming `a` is not the third value, is it true?"
The question "Is `a` false?" would have to be `!*a`, which is actually
"assuming `a` is not the third value, is it true?"

So a three-way if with optional<bool> would look like:

if(!a) {
// third value
} else if(*a) {
// true
} else {
// false
}

I prefer something like boost::tribool.

tribool a = true;
assert(bool(a) == true);
assert(bool(!a) == false);

tribool b = false;
assert(bool(a) == false);
assert(bool(!a) == true);

tribool c = third;
assert(bool(c) == false);
assert(bool(!c) == false);

With this `bool(a)` means "Is `a` true?", and `bool(!a)` means "Is `a`
false?". The third value, not being true nor false yields "no" for
both queries.

So a three-way if looks like:

if(a) {
// true
} else if(!a) {
// false
} else {
// third value
}

Another thing to notice is that `operator!` works as expected with
tribool: the negation of true is false, and the negation of false is
true. The negation of an indeterminate value is indeterminate (it acts
a bit like NaN in floating point arithmetic; call it not-a-boolean ;).
With optional<bool> the negation of false is false.

I prefer to restrict my usage of optional<bool> for incidental
occurrences in generic code, and not as a tri-valued boolean. I don't
need it often, but I wouldn't mind having a tribool type in the
standard library, as long as it is not some "object-oriented"
nonsense.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Fernando Cacciola
2013-06-27 02:30:23 UTC
Permalink
On Wed, Jun 26, 2013 at 1:11 PM, Martinho Fernandes <
Post by Greg Marr
std::bool_intermediate for states that are not true or false. ...
Also, std::bool_intermediate take into account the superposition of the two
boolean states.
Post by Greg Marr
This sounds exactly like std::optional<bool>.
I think `optional<bool>` has confusing semantics to be used for
tri-value logic.
FWIW, I totally agree with you here, and in fact, we have boost::tribool
precisely because boost::optional<bool> didn't quite cut it.

I thought about having core support for tribool but it's quite tricky to
get right, and pure library support is actually enough, even if not as
convenient.

I use triboolean logic all over the place when I work on a very specific
(and specialized) domain, for which I write code like:

if ( certainly(b) )
{
// b == true
}
else if ( certainly_not(b) )
{
// b == false
}
else
{
// b is indeterminate (or neither true nor false if we consider a more
general lattice type)
}

I'm not fond of the extra verbosity or the fact that the triboolean
expression b must be evaluated twice (unless is set aside before the
statement), but I can live with that.

So, is there any proposal for tribool already?

Best
--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Bjorn Reese
2013-06-27 08:56:20 UTC
Permalink
Post by Fernando Cacciola
I thought about having core support for tribool but it's quite tricky to
get right, and pure library support is actually enough, even if not as
convenient.
You should also consider the behavior of the logical operators. I have
had use cases where I could not use boost::tribool because it truth
table did not match my needs. Instead I needed operators that always
yielded determinate values (true/false) unless both operands were
indeterminate. I am going to call this boolean type for neutral bool
below.

I have listed the truth tables of the two below. I use F = false, T =
true, and N = none/indeterminate.

The truth tables for boost::tribool:

NOT |
----+---
F | T
T | F
N | N

AND | F T N
----+-------
F | F F F
T | F T N
N | F N N

OR | F T N
----+-------
F | F T N
T | T T T
N | N T N

The truth tables for neutral bool:

NOT |
----+---
F | T
T | F
N | N

AND | F T N
----+-------
F | F F F
T | F T T
N | F T N

OR | F T N
----+-------
F | F T F
T | T T T
N | F T N

There may also be a valid use case for a NaN-like tribool that always
yields indeterminate if either operand is indeterminate, but I am not
going to elaborate on that here.
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Fernando Cacciola
2013-06-27 12:23:08 UTC
Permalink
Post by Fernando Cacciola
I thought about having core support for tribool but it's quite tricky to
Post by Fernando Cacciola
get right, and pure library support is actually enough, even if not as
convenient.
You should also consider the behavior of the logical operators. I have
had use cases where I could not use boost::tribool because it truth
table did not match my needs. Instead I needed operators that always
yielded determinate values (true/false) unless both operands were
indeterminate. I am going to call this boolean type for neutral bool
below.
Interesting.

Following your truth table below, I would say that, ultimately, you need:

a & b -> possibly ( a & b ) // if using tribool

a | b -> certainly( a | b ) // if using tribool

everything else seems to match tribool.

Would you be able to use the equivalence above and stick to tribool?


Regarding core support, here is where I am at the moment, FWIW:

The difficulty boils down to the fact that there are two paths to reduce
from tribool to bool.

We have:

certainly(b) == true IFF b = true
certainly_not(b) == true IFF b = false
possibly(b) == true IFF b != false
possibly_not(b) == true IFF b != true

thus, given

tribool tb ;

foo ( bool ) ; foo(tb);
if ( tb )
tb ?
while(tb)

all of them coluld be equivalent to reducing via certainly or possibly, but
arbitraryly picking one doesn't seem right.

For example, I normally write

if ( certainly(tb) )
else if ( certainly_not(tb) )
else // only indeterminate falls here

but it's also quite reasonable to do

if ( certainly(tb) )
else // both false and indeterminate falls here

so it would not be at all evident what:

if ( tb )
else

actually means, NOT even if we guessed that if ( tb ) means if (
certainly(tb) )

my current preference goes to disallow entirely conversion to bool, not
even explicit, and add the following new keywords:

certainly_if
possibly_if
certainly_else
possibly_else

so that I can write:

certianly_if ( tb )
{
// tb == true for sure
}
certainly_else
{
// tb == false for sure
}
else
{
// can't tel
}

Granted, certainly_if ( tb ) is so much the same as if ( certainly(tb) )
that a new keyword seems totally unnecesary, but the real thing is the
_else keywords:

certainly_else
{
}

is much much better (IMHO) than

else if ( certainly_not(tb) )
{
}

so I like that one to be in core, but then the _if versions make sense just
for completeness

Best
--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Martinho Fernandes
2013-06-27 12:45:34 UTC
Permalink
On Thu, Jun 27, 2013 at 2:23 PM, Fernando Cacciola
Post by Fernando Cacciola
my current preference goes to disallow entirely conversion to bool, not
I don't think there's a good chance of getting new keywords for
something that is a bit of a niche and has proven library-only
implementations :(
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Bjorn Reese
2013-06-27 14:03:07 UTC
Permalink
If I understood your certainly/possibly functions correctly, the take a
tribool and returns a bool.
Post by Fernando Cacciola
a & b -> possibly ( a & b ) // if using tribool
This will give me

AND | F T N
----+-------
F | F F F
T | F T T
N | F T T

but I need N && N == N.
Post by Fernando Cacciola
a | b -> certainly( a | b ) // if using tribool
This will give me

OR | F T N
----+-------
F | F T F
T | T T T
N | F T F

but I need N || N == N.

Maybe neutral bool could be handled via a policy or trait of tribool?
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Fernando Cacciola
2013-06-27 15:03:36 UTC
Permalink
Post by Bjorn Reese
If I understood your certainly/possibly functions correctly, the take a
tribool and returns a bool.
a & b -> possibly ( a & b ) // if using tribool
This will give me
AND | F T N
----+-------
F | F F F
T | F T T
N | F T T
but I need N && N == N.
a | b -> certainly( a | b ) // if using tribool
This will give me
OR | F T N
----+-------
F | F T F
T | T T T
N | F T F
but I need N || N == N.
OK.I actually noticed that but didn't pay attention since it matched tribol
behavior.

I went the posibly|cerainly road as an attempt to follow why would you need
such a behavior.
When you ask: "is a AND b", and you cannot tell a or b, then IMO the answer
is 'how should I know". Which is why N/F AND N/F is N in tribool

So, it looked like you are asking more like: "could it be a AND b", hence
my version. But I'm still suspicious, "I don't know" and "yes" are not
"yes" both at the same time.

Now....

AND and OR can be generalized as a count_true function such that:

a AND b AND c AND d means

count_true( answers )==answers.count

a OR b OR c OR d means

count_true( answers )==1
Post by Bjorn Reese
From this POV, you seem to need to know whether all of the *actual* answers
are true at the same time (or at least one in the case of |).
That is:

actual_answers=filter_out_indeterminate(answers);

your AND -> count_true(actual_answers)==actual_answers.count with .count !=
0

your OR -> count_true(actual_answers)==1


Thus, it looks to me that your real need are specialized AND/OR as opposed
to a specialized Truth Table.
That is, we could have tribool and you could have you own AND/OR functions
that do what you want, which, like I said, looks to me that as just
filtering out the indeterminate.
Post by Bjorn Reese
Maybe neutral bool could be handled via a policy or trait of tribool?
For something like this, a policy would be overkill. But this is a
different discussion.

Best
--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Fernando Cacciola
2013-06-27 18:36:51 UTC
Permalink
On Thu, Jun 27, 2013 at 12:03 PM, Fernando Cacciola <
Post by Fernando Cacciola
That is, we could have tribool and you could have you own AND/OR functions
that do what you want, which, like I said, looks to me that as just
filtering out the indeterminate.
Well, here is something interesting.

These days I'm creating a DSL for SQL query construction, and I was just
looking at the following real code I've created with it:

Schemas.Doc.Id.Is( aDocModel.Id )
| ( Schemas.Doc.Label.Is( aDocModel.Name)
& Schemas.DocCategory.Category.IsAnyOf(aDocModel.Tags)
)

That code there creates an string that can be added to a WHERE SQL clause.

I wanted this to be super easy to use by the "end-user" programmers, so I
made it such that, if any of the "input values" are null, the expression
automatically reduces.
That is,

if aDocMode.Id is null (or empty in this case as it is a string), then the
above is actually equivalent to just:

Schemas.Doc.Label.Is( aDocModel.Name)
& Schemas.DocCategory.Category.IsAnyOf(aDocModel.Tags)

Similarly, if, OTOH, aDocModel.Tags, which is a sequence, happens to be
empty, it reduces to:

Schemas.Doc.Id.Is( aDocModel.Id )
| Schemas.Doc.Label.Is( aDocModel.Name)


Now, I just realized that, IIUC, this exactly matches the net effect of
your choice of semantic for & and | with your neutral tribool.
In fact, I might even implemented this using your type.

So, FWIW I found real use cases as I wanted.

Best
--
Fernando Cacciola
SciSoft Consulting, Founder
http://www.scisoft-consulting.com
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Bjorn Reese
2013-06-29 10:04:25 UTC
Permalink
Post by Fernando Cacciola
So, FWIW I found real use cases as I wanted.
Intriguingly, my real-world use case also came from an SQL-like setting.
I had to examine if two rows were similar by comparing their entries
pairwise. Each entry could be null, but the result of the pairwise
comparison should only be null if both entries were null. The results
of each pairwise comparison was then aggregated into the final result.
By having the pairwise comparison operator return a neutral bool, the
aggregation simply became:

neutral_bool has_artist = row1.artist == row2.artist;
neutral_bool has_album = row1.album == row2.album;
neutral_bool result = has_artist && has_album;

The actual code did not use the intermediate has_artist and has_album
variables, and there were more entries that the two listed above.

Regarding the use of traits, I put together a simple prototype of
tribool that uses traits to obtain both the traditional tribool
behavior and the neutral bool behavior. Pretty straigh-forward.

https://github.com/breese/tribool/blob/master/include/tribool
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Mikhail Semenov
2013-06-30 07:48:38 UTC
Permalink
Multi-value logic (and tribool is part of it) is based on the fact that
you use values 0,...,n (total n+1) :
not(v) = n-v

and(v1,...,vk) = min(v1,...,vk)

or(v1,...,vk) = max(v1,...,vk)

In case of tribool (n=2):
F = 0
N = 1
T = 2
And all the truth tables can be easily derived.
You can further with logic:
F - not true // impossible
N - unknown likelihood
T - true // certain

certain(v) iff v = T
uncertain(v) iff v < T
possible(v) iff v > F
impossible(v) iff v = F
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Bjorn Reese
2013-06-30 09:38:04 UTC
Permalink
Post by Mikhail Semenov
Multi-value logic (and tribool is part of it) is based on the fact that
This reminded me of N2136 "Bool_set: multi-valued logic"

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2136.pdf

The most recent status of this proposal that I could find is:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3371.html
--
---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.
Loading...