[tribool] short-circuting issue with overloads of operator|| and operator&&

Hi, I've just used a tribool and a null pointer together in an if-expression: if (a_tribool || *a_bool_pointer) ... leading to an access violation, because operator || is overloaded for tribool and dereferencing the pointer occurs before calling operator || instead of short-circuiting the expression. Is this by design and do I have to access the tribool's 'value' member directly? Thanks, Klaus Triendl

Is this by design and do I have to access the tribool's 'value' member directly?
I wouldn't say it's "by design" - rather it's an unfortunate limitation of C++ that overloaded boolean operators cannot emulate the short-circuiting behaviour as with builtin types. You could try something like: if ((a_tribool == true) || *a_bool_pointer) to convert the left-hand side back to a native bool and get the short-circuiting. Regards, Alex

Alex MDC schrieb:
Is this by design and do I have to access the tribool's 'value' member directly?
I wouldn't say it's "by design" - rather it's an unfortunate limitation of C++ that overloaded boolean operators cannot emulate the short-circuiting behaviour as with builtin types.
Hmm, I didn't look thoroughly at it but wouldn't it be possible to remove these overloads? I've seen a proposal for bool_set that doesn't overload (anymore) the two logical operators. -- Klaus

On Tue, May 20, 2008 at 4:13 PM, klaus triendl <klaus@triendl.eu> wrote:
Hmm, I didn't look thoroughly at it but wouldn't it be possible to remove these overloads? I've seen a proposal for bool_set that doesn't overload (anymore) the two logical operators.
I don't think you can get rid of the overloads. The overloads are needed to implement the truth tables (see http://www.boost.org/doc/libs/1_35_0/doc/html/boost/logic/operator_id257657.... http://www.boost.org/doc/libs/1_35_0/doc/html/boost/logic/operator!_id340819... ). In order to remove them, you need a conversion C: tribool-> bool that preserves all the truth tables, and is an homomorphism, i.e. C( op(X) ) == op( C(X) ) and C( X op Y ) == C(X) op C(Y) Unfortunately, if such conversion existed, then : C(indeterminate) = C(!indeterminate) = !C(indeterminate) that is impossible for a bool. Do you really need tribool semantics, or you just needed something like optional<bool>? One thing that can be done is to use expression templates to build the operator expressions, and implement short circuit evaluation on top of them, but then you have to pay attention to how you build your expression, because you have to explicitly delay expressions like *a_bool_pointer. Corrado --
Klaus
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:czoccolo@gmail.com PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

On Wed, May 21, 2008 at 1:57 AM, Corrado Zoccolo <czoccolo@gmail.com> wrote:
I don't think you can get rid of the overloads. The overloads are needed to implement the truth tables (see http://www.boost.org/doc/libs/1_35_0/doc/html/boost/logic/operator_id257657.... http://www.boost.org/doc/libs/1_35_0/doc/html/boost/logic/operator!_id340819... ).
Wouldn't it make more sense to use operator| instead of operator|| ? When used in the context of boolean algebra, the former always carries with it the expectation that there will be no short-circuiting. The lack of short-circuiting makes overloading operator|| a headache for users (though I can't imagine how you'd implement it to allow short-circuiting). The same (obviously) applies to operator&& as well. :) - Jim

Jim wrote:
Wouldn't it make more sense to use operator| instead of operator|| ? When used in the context of boolean algebra, the former always carries with it the expectation that there will be no short-circuiting. The lack of short-circuiting makes overloading operator|| a headache for users (though I can't imagine how you'd implement it to allow short-circuiting).
I'm going to agree with Jim here. The bitwise operators are a better choice for overloading than the logical, which imply flow control. I also agree with him that short-circuiting can't be implemented. If you have expression templates as someone else suggested you could short circuit evaluating your own expressions, but not short circuit evaluating other code, only the compiler can do that: A || B || foo(C); The compiler won't even look at your || operator until after it has called foo. You must evaluate foo before you construct your expression template, and you could short circuit looking at its result if A or B were true, but you couldn't prevent it from being called on C in the first place. Luke

On Wed, May 21, 2008 at 6:28 PM, Simonson, Lucanus J < lucanus.j.simonson@intel.com> wrote:
I'm going to agree with Jim here. The bitwise operators are a better choice for overloading than the logical, which imply flow control.
There is still a problem with this approach. The non overloaded operators || and && will usually do the wrong thing, causing the tribool to be first converted to bool, and then to go through the short-circuited evaluation. This means relations like: !a && !b == !(a || b) will not hold any more (just take a and b to be indeterminate). This will be much more surprising, IMO. You should disable operators || and && completely using private overloads. I also agree with him that short-circuiting can't be implemented. If you
have expression templates as someone else suggested you could short circuit evaluating your own expressions, but not short circuit evaluating other code, only the compiler can do that:
A || B || foo(C);
In my post, I said that the final user still has to delay the calls to his code to make the ET approach work, so it is not transparent. This is usual for expression templates that represent code to be evaluated, look for example at boost::lambda. Corrado Luke
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- __________________________________________________________________________ dott. Corrado Zoccolo mailto:czoccolo@gmail.com PhD - Department of Computer Science - University of Pisa, Italy -------------------------------------------------------------------------- The self-confidence of a warrior is not the self-confidence of the average man. The average man seeks certainty in the eyes of the onlooker and calls that self-confidence. The warrior seeks impeccability in his own eyes and calls that humbleness. Tales of Power - C. Castaneda

Corrado Zoccolo wrote:
There is still a problem with this approach. The non overloaded operators || and && will usually do the wrong thing, causing the tribool to be first converted to bool, and then to go through the short-circuited evaluation. [snip] You should disable operators || and && completely using private overloads.
That's true. It would probably cause some initial confusion, but better to be surprised with a compiler error than an obscure logic error! :) There's also the issue of backwards-compatibility, but I think the default behavior should be to throw a compiler error when attempting to use operators || or && with a tribool. That could be resolved with a simple preprocessor macro to re-enable || and &&, though. - Jim

Alex MDC schrieb:
You could try something like: if ((a_tribool == true) || *a_bool_pointer) to convert the left-hand side back to a native bool and get the short-circuiting.
This doesn't help either because operator== is overloaded and returns again a tribool. -- Klaus
participants (5)
-
Alex MDC
-
Corrado Zoccolo
-
James Porter
-
klaus triendl
-
Simonson, Lucanus J