Is there a "very bad thing" that can happen &&=
and ||=
were used as syntactic sugar for bool foo = foo && bar
and bool foo = foo || bar
?
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.
||
and &&
shortcut, i.e. the second argument isn't operand if the first operand is true
(resp. false
for &&
). |
, &
, |=
and &=
always evaluate both operands. –
Fechner a &&= b
? I think that’s asking for trouble. –
Gpo switch
on the above b
, it is likely you end up in default:
even if you have both true and false branches. –
Florettaflorette &=
for a left-hand side of type bool
, because it's perfectly possible for the right-hand side to be of type other than bool
(such as islower
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 to bool
, which &=
does not. In other words, bool b = true; b &= 2;
results in b == false
. –
Inexorable 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. –
Gpo bool
". One could read just the highlighted part and bring home the wrong message. –
Tillich reinterpret_cast<>()
in this statement bool b = *reinterpret_cast<bool*>(&i);
is not going to do what you think on Big Endian machines. You would need to check the size of bool
(probably 1 byte, probably 8 on a CRAY, though) and based on that use an int
type of the right size. –
Lapsus &&
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();
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();
success = success && DoImportantStuff()
–
Emanative if(success) success = DoImportantStuff()
. If the statement success &&= DoImportantStuff()
was allowed, many developers would think DoImportantStuff()
is always called whatever the value of success
. 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 ;-) –
Conversation success &&= DoImportantStuff()
was allowed, many developers would think DoImportantStuff()
is always called whatever the value of success." You can say that about if (success && DoImportantStuff())
though. As long as they remember the logic behind the if syntax they should have no trouble with &&=
. –
Thorpe f1()
always evaluates in ok &&= f(1)
but won't assume it always evaluates in ok = ok && f(1)
. Seems just as likely to me. –
Parallelogram ok=f();
or ok+=f();
or ok%=f();
or ok&=f();
you expect some value will be stored in variable ok
. Therefore most of brains also expect ok&&=f();
will store a value in ok
. Do you feel what I mean? There is also something I do not mention yet in the answer: sequence points. The statement ok=f();
has one sequence point: the final ;
The statement ok=ok&&f();
has two sequence points: &&
and ;
. Operators =
cannot be a sequence point in languages C and C++. –
Conversation v1 += e2
to be the syntactic sugar equivalent of v1 = v1 + e1
for variable v1 and expression e2. Just a shorthand notation, that's all. –
Parallelogram f()
will always be called in both cases: ok |= f();
and ok ||= f();
whatever the value of ok
. This is only exact for ok |= f();
. I am very surprised that you thought f()
will not be called if ok
was already true
. 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 ;-) –
Conversation x = x || y
and x = x && y
to have different behaviours than x ||= y
and x &&= y
, which I... can see being a plausible assumption in some cases, but really don't like. xD –
Kiblah b &&= dostuff1(); b &&= dostuff2(); ... if (b) set_dirty();
for example. –
Million short circuiting is important, and the semantics are straightforward. A &&= B would be syntactic sugar for A = A && B.
The concept of monadic programming was not widespread in the early days of K&R, so it seems the best explanation is K&R didn't think it was important, and like the QWERTY keyboard, we've lived with it ever since.
© 2022 - 2024 — McMap. All rights reserved.
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. – Cinchonize&&=
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. – Thermobarographbool 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. – Thermobarographbool
, and these operations only really make sense forbool
type. – Ozonosphere