When used with boolean
operands, &
and |
become logical operators per Section 15.22.2 of the JLS. Unlike &&
and ||
, however, these don't short-circuit; they always evaluate both sides. I have a silly question: Why are the less-efficient non-short-circuit logical operators (&
, |
) still there, when we have the more-efficient short-circuit logical operators (&&
, ||
)? I mean, what is the real usage of the non-short-circuit logical operators, as opposed to with the short-circuit logical operators? In other words, what is the usage of always evaluating both sides by using the non-short-circuit logical operators?
Consider the case where you want any side-effects to always occur, regardless of whether the left-hand expression evaluates true
or false
. E.g., contrast:
if (foo() & bar()) {
// Only call this if both operations returned true
}
with
if (foo() && bar()) {
// Only call this if both operations returned true
}
Let's assume both foo
and bar
have effects that we want to have happen regardless of whether foo
returns true
or false
. In the first one above, I know that bar
will always get called and have its effect. In the latter, of course, bar
may or may not get called. If we didn't have the non-short-circuit version, we'd have to use temporary variables:
boolean fooResult = foo();
boolean barResult = bar();
if (fooResult && barResult) {
// ...
}
You might argue (I probably would) that you should do that anyway, because it's way too easy to misread if (foo() & bar())
, but there we go, a pragmatic reason for having non-short-circuit versions.
&
and |
. I wouldn't recommend it unless a) you're really really keen on performance, and b) you can produce benchmark data to support you. –
Trapeziform non-short-circuit
logic(especially not everywhere, but in some places) seems like a flaw in code design for me. It makes you keep in mind the fact that all elements of expression will have its effect. –
Gnni There are instances where the components of a boolean expression involve operations that you'd want to have executed in all cases. Consider the following example of checking a password for validity:
while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) {
// re-prompt
}
If the second condition was not evaluated due to short-circuiting, attempts
would never be incremented. Thus greater programmer flexibility is enabled.
&&
too if change the order :) –
Lacefield My case (C++):
void setFields(Parameters bundle)
{
if (setIfDifferent(&field1, bundle.value1) |
setIfDifferent(&field2, bundle.value2) |
setIfDifferent(&field3, bundle.value3)) {
storeState();
}
}
setIfDifferent() sets the object's field with new value if they differ, in which case it returns true; or it returns false in case the field's and the new value are the same. So, we want to try to set all fields, and if any of them changed, then we want to store new object's state.
You can have some side-effects in logical expression, for example you can assign simultaneously with checking. This may work wrongly if only one part evaluated.
Can't remember good example now, but remember that I was in need of "non-short-circuit" operators sometimes.
Hmmm.... Below is WRONG example, which won't work without "non-short-circuit" OR:
if( (object1=getInstance1()).getNumber() == 1 || (object2=getInstance2()).getNumber() == 2 ) {
// do something which requires bot object1 and object2 assigned
}
In my case, I have two methods that compare two different but related objects (Object2 is an attribute of Object1) to see if there were any changes. An update needs to happen if either are updated, but both need to be evaluated so that the objects will be modified if both have been changed. Therefore, a single pipe "OR" comparison is required.
EX:
if (compare(object1, currentObject1) | comparison(object2, currentObject2)) {
updateObject1(object1);
}
Technically, & and | are not logical, they're bitwise operators that become logical operators when associated with booleans.
There are times when you'd want to include assignment expressions inside your logical expressions.
Say:
if(a = (checkForSomeCondition()) | b = checkForAnotherCondition())
{
//now do something here with a and b that has been cached
}
If I had used ||, I'd not be able to perform the above check and would have had to split the assignments into separate statements. I've never come across scenarios like this during application development, but come across it a few times while writing algorithms.
Of course, you could use unary operators on the logical expressions or pass variables by reference into a predicate, but those seem like less common cases than the above.
© 2022 - 2024 — McMap. All rights reserved.
&
and|
. Like Java, it short-circuits&&
and||
, but not&
and|
. – Laudable