Why doesn't c++ have &&= or ||= for booleans?
Solution 1
A bool
may only be true
or false
in C++. As such, using &=
and |=
is relatively safe (even though I don’t particularly like the notation). True, they will perform bit operations rather than logical operations (and thus they won’t short-circuit) but these bit operations follow a well-defined mapping, which is effectively equivalent to the logical operations, as long as both operands are of type bool
.1
Contrary to what other people have said here, a bool
in C++ must never have a different value such as 2
. When assigning that value to a bool
, it will be converted to true
as per the standard.
The only way to get an invalid value into a bool
is by using reinterpret_cast
on pointers:
int i = 2;
bool b = *reinterpret_cast<bool*>(&i);
b |= true; // MAY yield 3 (but doesn’t on my PC!)
But since this code results in undefined behaviour anyway, we may safely ignore this potential problem in conforming C++ code.
1 Admittedly this is a rather big caveat as Angew’s comment illustrates:
bool b = true;
b &= 2; // yields `false`.
The reason is that b & 2
performs integer promotion such that the expression is then equivalent to static_cast<int>(b) & 2
, which results in 0
, which is then converted back into a bool
. So it’s true that the existence of an operator &&=
would improve type safety.
Solution 2
&&
and &
have different semantics: &&
will not evaluate the second operand if the first operand is false
. i.e. something like
flag = (ptr != NULL) && (ptr->member > 3);
is safe, but
flag = (ptr != NULL) & (ptr->member > 3);
is not, although both operands are of type bool
.
The same is true for &=
and |=
:
flag = CheckFileExists();
flag = flag && CheckFileReadable();
flag = flag && CheckFileContents();
will behave differently than:
flag = CheckFileExists();
flag &= CheckFileReadable();
flag &= CheckFileContents();
Solution 3
Short answer
All the operators +=
, -=
, *=
, /=
, &=
, |=
... are arithmetic and provide same expectation:
x &= foo() // We expect foo() be called whatever the value of x
However, operators &&=
and ||=
would be logical, and these operators might be error-prone because many developers would expect foo()
be always called in x &&= foo()
.
bool x;
// ...
x &&= foo(); // Many developers might be confused
x = x && foo(); // Still confusing but correct
x = x ? foo() : x; // Understandable
x = x ? foo() : false; // Understandable
if (x) x = foo(); // Obvious
Do we really need to make C/C++ even more complex to get a shortcut for
x = x && foo()
?Do we really want to obfuscate more the cryptic statement
x = x && foo()
?
Or do we want to write meaningful code likeif (x) x = foo();
?
Long answer
Example for &&=
If &&=
operator was available, then this code:
bool ok = true; //becomes false when at least a function returns false
ok &&= f1();
ok &&= f2(); //we may expect f2() is called whatever the f1() returned value
is equivalent to:
bool ok = true;
if (ok) ok = f1();
if (ok) ok = f2(); //f2() is called only when f1() returns true
This first code is error-prone because many developers would think f2()
is always called whatever the f1()
returned value. It is like writing bool ok = f1() && f2();
where f2()
is called only when f1()
returns true
.
- If the developer actually wants
f2()
to be called only whenf1()
returnstrue
, therefore the second code above is less error-prone. - Else (the developer wants
f2()
to be always called),&=
is sufficient:
Example for &=
bool ok = true;
ok &= f1();
ok &= f2(); //f2() always called whatever the f1() returned value
Moreover, it is easier for compiler to optimize this above code than that below one:
bool ok = true;
if (!f1()) ok = false;
if (!f2()) ok = false; //f2() always called
Compare &&
and &
We may wonder whether the operators &&
and &
give the same result when applied on bool
values?
Let's check using the following C++ code:
#include <iostream>
void test (int testnumber, bool a, bool b)
{
std::cout << testnumber <<") a="<< a <<" and b="<< b <<"\n"
"a && b = "<< (a && b) <<"\n"
"a & b = "<< (a & b) <<"\n"
"======================" "\n";
}
int main ()
{
test (1, true, true);
test (2, true, false);
test (3, false, false);
test (4, false, true);
}
Output:
1) a=1 and b=1
a && b = 1
a & b = 1
======================
2) a=1 and b=0
a && b = 0
a & b = 0
======================
3) a=0 and b=0
a && b = 0
a & b = 0
======================
4) a=0 and b=1
a && b = 0
a & b = 0
======================
Conclusion
Therefore YES we can replace &&
by &
for bool
values ;-)
So better use &=
instead of &&=
.
We can consider &&=
as useless for booleans.
Same for ||=
operator
|=
is also less error-prone than||=
If a developer wants f2()
be called only when f1()
returns false
, instead of:
bool ok = false;
ok ||= f1();
ok ||= f2(); //f2() is called only when f1() returns false
ok ||= f3(); //f3() is called only when f1() or f2() return false
ok ||= f4(); //f4() is called only when ...
I advice the following more understandable alternative:
bool ok = false;
if (!ok) ok = f1();
if (!ok) ok = f2();
if (!ok) ok = f3();
if (!ok) ok = f4();
// no comment required here (code is enough understandable)
or if you prefer all in one line style:
// this comment is required to explain to developers that
// f2() is called only when f1() returns false, and so on...
bool ok = f1() || f2() || f3() || f4();
Kache
Updated on July 16, 2020Comments
-
Kache almost 4 years
Is there a "very bad thing" that can happen
&&=
and||=
were used as syntactic sugar forbool foo = foo && bar
andbool foo = foo || bar
?-
jamesdlin about 14 yearsSee this other question: stackoverflow.com/questions/2324549/… That one's about Java, but sharing the C lineage, the same arguments mostly apply.
-
Kache about 14 yearsBasically, just c++ doesn't have it b/c they didn't put it in - languages like Ruby has it. boo...
-
Steve Jessop about 14 yearsBut in Ruby, isn't
x ||= y
roughly equivalent to C++x = x ? x : y;
for any type? In other words, "set to y if not already set". That's considerably more useful than C or C++x ||= y
, which (barring operator overloading) would do "set x to(bool)y
unless already set". I'm not anxious to add another operator for that, it seems a bit feeble. Just writeif (!x) x = (bool)y
. But then, I don't really usebool
variables enough to want extra operators that are only really useful with that one type. -
Jonathan Leffler almost 9 yearsI'm sure the primary reason C++ doesn't have
&&=
or||=
is simply that C doesn't have them. I'm reasonably sure the reason C doesn't have them is that the functionality wasn't deemed beneficial enough. -
Jonathan Leffler almost 9 yearsAlso, being ultra-pedantic, the notation
bool foo = foo || bar;
would invoke undefined behaviour becausefoo
is not initialized prior to the evaluation offoo || bar
. Of course, this is intended to be something likebool foo = …initialization…; …; foo = foo || bar;
and the question then stands as valid.
-
-
dan04 about 14 yearsBut the && and || operators will work on anything that converts to bool, not just bool.
-
Niki about 14 yearsThey don't do the same thing, even on bools.
||
and&&
shortcut, i.e. the second argument isn't operand if the first operand istrue
(resp.false
for&&
).|
,&
,|=
and&=
always evaluate both operands. -
Konrad Rudolph about 14 years@nikie: I didn’t say that they did the same. And do you really want to short-circuit an assignment such as
a &&= b
? I think that’s asking for trouble. -
Kache about 14 yearsall the more reason to have &&= in my opinion. =P
-
Johannes Schaub - litb about 14 yearsIn fact, if you try to do a
switch
on the aboveb
, it is likely you end up indefault:
even if you have both true and false branches. -
Konrad Rudolph about 14 years@Johannes: The UB case? Yes, that’s possible. But I’ve tested this and on my PC (OS X 10.5, GCC 4.4.2) it actually doesn’t – which kind of surprised me, too.
-
Niklas R almost 11 yearsWhat if I actually want this behaviour? That the right hand expression is not executed if the left hand expression is wrong. It is annoying to write the variables two times, like
success = success && DoImportantStuff()
-
oHo almost 11 yearsMy advice is to write
if(success) success = DoImportantStuff()
. If the statementsuccess &&= DoImportantStuff()
was allowed, many developers would thinkDoImportantStuff()
is always called whatever the value ofsuccess
. Hope this answers what you wonder... I have also improved many parts of my answer. Please tell me if my answer is more understandable now? (about your comment purpose) Cheers, See you ;-) -
pilkch almost 10 years"If the statement
success &&= DoImportantStuff()
was allowed, many developers would thinkDoImportantStuff()
is always called whatever the value of success." You can say that aboutif (success && DoImportantStuff())
though. As long as they remember the logic behind the if syntax they should have no trouble with&&=
. -
thang about 9 yearsthis doesn't answer the question of why &&= and ||= are not c++ operators.
-
Konrad Rudolph about 9 years@ethang I chose to answer the question in the actual text body rather than the one in the title. Admittedly, it’s hard to know whether that was appropriate since the title and the body of the question contradicted each other. Yet the OP seems to be happy. At any rate, there’s no real answer to the question in the title, except “because.” — Nobody made a corresponding proposal to the standards committee, or any such proposal was vetoed.
-
einpoklum over 8 yearsIn addition to @dan04 's comment (from 6 years ago...) - bools very often convert to ints for all sorts of reasons, and the &&= would make sure everything is boolean again
-
einpoklum over 8 yearsI don't see how people may assume that
f1()
always evaluates inok &&= f(1)
but won't assume it always evaluates inok = ok && f(1)
. Seems just as likely to me. -
oHo over 8 yearsHi @einpoklum Good question and I think I should improve my answer... I mean when you see a statement
ok=f();
orok+=f();
orok%=f();
orok&=f();
you expect some value will be stored in variableok
. Therefore most of brains also expectok&&=f();
will store a value inok
. Do you feel what I mean? There is also something I do not mention yet in the answer: sequence points. The statementok=f();
has one sequence point: the final;
The statementok=ok&&f();
has two sequence points:&&
and;
. Operators=
cannot be a sequence point in languages C and C++. -
einpoklum over 8 yearsI actually expect
v1 += e2
to be the syntactic sugar equivalent ofv1 = v1 + e1
for variable v1 and expression e2. Just a shorthand notation, that's all. -
arun s almost 8 years"operator |= is also less error-prone than ||= " , Really? People make mistakes either ways. I just discovered an error in my code where I found that my assumption that line ok |= f(); will not evaluate 'f' if ok is already true is false.
-
oHo almost 8 yearsHi @aruns. Thanks for for feedback :-) Most developers will think the function
f()
will always be called in both cases:ok |= f();
andok ||= f();
whatever the value ofok
. This is only exact forok |= f();
. I am very surprised that you thoughtf()
will not be called ifok
was alreadytrue
. Do not forget: you do not write code to be understandable for the compiler, you first write code to be understandable by your colleagues. Therefore I propose this more readable syntax:if (! ok) f();
. Do you agree? Cheers ;-) -
Angew is no longer proud of SO over 7 yearsIt's not safe to use
&=
for a left-hand side of typebool
, because it's perfectly possible for the right-hand side to be of type other thanbool
(such asislower
or another C stdlib function which returns nonzero for true value). If we had the hypothetical&&=
, it would probably force the right-hand side to convert tobool
, which&=
does not. In other words,bool b = true; b &= 2;
results inb == false
. -
Konrad Rudolph over 7 years@Angew That’s why I wrote “as long as both operands are indeed of type
bool
.” But you’re right that implicit conversion (and in particular integer promotion) make this usage less safe than a hypothetical&&=
. I’ll add a footnote to my answer. -
Antonio over 6 yearsDownvoted because your highlighting doesn't include "as long as both operands are indeed of type
bool
". One could read just the highlighted part and bring home the wrong message. -
Konrad Rudolph over 6 years@Antonio Tough crowd. 😝
-
Catskul about 5 yearsThis isn't really an answer though.
-
Justin Time - Reinstate Monica almost 5 yearsThis assumes that programmers will expect
x = x || y
andx = x && y
to have different behaviours thanx ||= y
andx &&= y
, which I... can see being a plausible assumption in some cases, but really don't like. xD -
Apollys supports Monica over 4 yearsWhy is this the top answer? How is this even an answer of any sort?
-
Apollys supports Monica over 4 yearsBest answer by far (really the only one that addresses the question).
-
Konrad Rudolph over 4 years@Apollys What are you missing from it? Speculations about the language designers’ motives? These are generally seen as unreliable, subjective and off-topic here. We don’t know why. Case in point, olibre’s answer is pure speculation despite sounding authoritative. By contrast, this answer gives technical reasons for why having them isn’t all that useful, which might be the underlying cause.
-
Alexis Wilke almost 4 yearsNote that your
reinterpret_cast<>()
in this statementbool b = *reinterpret_cast<bool*>(&i);
is not going to do what you think on Big Endian machines. You would need to check the size ofbool
(probably 1 byte, probably 8 on a CRAY, though) and based on that use anint
type of the right size. -
Konrad Rudolph almost 4 years@AlexisWilke Absolutely. And the code is UB anyway. I could have made it more “portable” by abstracting away the size of a boolean (and endianness) but that would have distracted from the point I was making.