Enforce usage of scalar logical operators in conditional statements
Source:R/vector_logic_linter.R
vector_logic_linter.Rd
Usage of &
in conditional statements is error-prone and inefficient.
condition
in if (condition) expr
must always be of length 1, in which
case &&
is to be preferred. Ditto for |
vs. ||
.
Details
This linter covers inputs to if()
and while()
conditions and to
testthat::expect_true()
and testthat::expect_false()
.
Note that because &
and |
are generics, it is possible that
&&
/ ||
are not perfect substitutes because &
is doing
method dispatch in an incompatible way.
Moreover, be wary of code that may have side effects, most commonly
assignments. Consider if ((a <- foo(x)) | (b <- bar(y))) { ... }
vs. if ((a <- foo(x)) || (b <- bar(y))) { ... }
. Because ||
exits
early, if a
is TRUE
, the second condition will never be evaluated
and b
will not be assigned. Such usage is not allowed by the Tidyverse
style guide, and the code can easily be refactored by pulling the
assignment outside the condition, so using ||
is still preferable.
See also
linters for a complete list of linters available in lintr.
Examples
# will produce lints
lint(
text = "if (TRUE & FALSE) 1",
linters = vector_logic_linter()
)
#> <text>:1:10: warning: [vector_logic_linter] Use `&&` in conditional expressions.
#> if (TRUE & FALSE) 1
#> ^
lint(
text = "if (TRUE && (TRUE | FALSE)) 4",
linters = vector_logic_linter()
)
#> <text>:1:19: warning: [vector_logic_linter] Use `||` in conditional expressions.
#> if (TRUE && (TRUE | FALSE)) 4
#> ^
lint(
text = "filter(x, A && B)",
linters = vector_logic_linter()
)
#> <text>:1:13: warning: [vector_logic_linter] Use `&` in subsetting expressions.
#> filter(x, A && B)
#> ^~
# okay
lint(
text = "if (TRUE && FALSE) 1",
linters = vector_logic_linter()
)
#> ℹ No lints found.
lint(
text = "if (TRUE && (TRUE || FALSE)) 4",
linters = vector_logic_linter()
)
#> ℹ No lints found.
lint(
text = "filter(x, A & B)",
linters = vector_logic_linter()
)
#> ℹ No lints found.