Boolean operators && and ||
The shorter ones are vectorized, meaning they can return a vector, like this:
((-2:2) >= 0) & ((-2:2) <= 0)
# [1] FALSE FALSE TRUE FALSE FALSE
The longer form evaluates left to right examining only the first element of each vector, so the above gives
((-2:2) >= 0) && ((-2:2) <= 0)
# [1] FALSE
As the help page says, this makes the longer form "appropriate for programming control-flow and [is] typically preferred in if clauses."
So you want to use the long forms only when you are certain the vectors are length one.
You should be absolutely certain your vectors are only length 1, such as in cases where they are functions that return only length 1 booleans. You want to use the short forms if the vectors are length possibly >1. So if you're not absolutely sure, you should either check first, or use the short form and then use all
and any
to reduce it to length one for use in control flow statements, like if
.
The functions all
and any
are often used on the result of a vectorized comparison to see if all or any of the comparisons are true, respectively. The results from these functions are sure to be length 1 so they are appropriate for use in if clauses, while the results from the vectorized comparison are not. (Though those results would be appropriate for use in ifelse
.
One final difference: the &&
and ||
only evaluate as many terms as they need to (which seems to be what is meant by short-circuiting). For example, here's a comparison using an undefined value a
; if it didn't short-circuit, as &
and |
don't, it would give an error.
a
# Error: object 'a' not found
TRUE || a
# [1] TRUE
FALSE && a
# [1] FALSE
TRUE | a
# Error: object 'a' not found
FALSE & a
# Error: object 'a' not found
Finally, see section 8.2.17 in The R Inferno, titled "and and andand".
The answer about "short-circuiting" is potentially misleading, but has some truth (see below). In the R/S language, &&
and ||
only evaluate the first element in the first argument. All other elements in a vector or list are ignored regardless of the first ones value. Those operators are designed to work with the if (cond) {} else{}
construction and to direct program control rather than construct new vectors.. The &
and the |
operators are designed to work on vectors, so they will be applied "in parallel", so to speak, along the length of the longest argument. Both vectors need to be evaluated before the comparisons are made. If the vectors are not the same length, then recycling of the shorter argument is performed.
When the arguments to &&
or ||
are evaluated, there is "short-circuiting" in that if any of the values in succession from left to right are determinative, then evaluations cease and the final value is returned.
> if( print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(FALSE && print(1) ) {print(2)} else {print(3)} # `print(1)` not evaluated
[1] 3
> if(TRUE && print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 2
> if(TRUE && !print(1) ) {print(2)} else {print(3)}
[1] 1
[1] 3
> if(FALSE && !print(1) ) {print(2)} else {print(3)}
[1] 3
The advantage of short-circuiting will only appear when the arguments take a long time to evaluate. That will typically occur when the arguments are functions that either process larger objects or have mathematical operations that are more complex.