rror
is a package to make using classed conditions in R easier. It
contains utilities for creating, raising, and catching conditions
including but not limited to messages, warnings, and errors. It is built
on top of the base condition handling system, and is fully compatible
with it.
rror
is not on CRAN yet, but can be installed from GitHub with
# install.packages("remotes")
remotes::install_github("alistaire47/rror")
Conditions are a formalized way of providing feedback to the user and
handling runtime issues. In most languages, conditions include errors
and warnings; in R, messages (usually generated with message()
,
equivalent to warning()
or stop()
) are also conditions, used for
generating diagnostic messages for the user.
R also has infrastructure to create, raise, and handle conditions of your own creation, which may or may not inherit from one of the built-in conditions.
The condition handling system of R is very powerful, but unfortunately most users don’t take advantage of its full power, because it is not trivial to understand, a process further hindered by limited documentation.
rror
makes it very simple to leverage more of the power of this
system—in particular working with classed errors. For instance, if a
package maintainer is validating arguments and wants to raise an error
for bad input, instead of generating a simpleError
from stop()
, e.g.
plus1 <- function(x) {
if (!is.numeric(x)) {
stop("`x` must be numeric")
}
x + 1
}
plus1(2)
#> [1] 3
tryCatch(
plus1("a"),
error = function(e) str(e)
)
#> List of 2
#> $ message: chr "`x` must be numeric"
#> $ call : language plus1("a")
#> - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
the maintainer can raise a classed error, e.g.
plus2 <- function(x){
if (!is.numeric(x)) {
rror::raise(rror::error_condition("`x` must be numeric", class = "value_error"))
}
x + 2
}
plus2(3)
#> [1] 5
rror::except(
plus2("b"),
value_error = function(e) str(e) # we can catch specific error classes!
)
#> List of 2
#> $ message: chr "`x` must be numeric"
#> $ call : language plus2(x = "b")
#> - attr(*, "capture_call")= logi TRUE
#> - attr(*, "class")= chr [1:3] "value_error" "error" "condition"
Common conditions can be predefined and reused.
rror
’s condition handling function, except()
, also has some benefits
over tryCatch()
. In particular, because the handlers registered in
tryCatch()
are exiting handlers, it is not very useful for suppressing
repeated warnings or messages and continuing:
f1 <- function(i) warning("warning ", i)
tryCatch(
{
for (i in 1:3) f1(i)
2 + 2
},
warning = function(w) print(w)
)
#> <simpleWarning in f1(i): warning 1>
except()
handles errors with exiting handlers, but non-fatal
conditions use local handlers, which lets specific errors be easily
suppressed:
f2 <- function(i) {
rror::raise(
rror::warning_condition(
paste("warning", i),
class = "number_warning"
)
)
}
rror::except(
{
for (i in 1:3) f2(i)
2 + 2
},
number_warning = function(w) print(w)
)
#> <number_warning in f2(i = i): warning 1>
#> <number_warning in f2(i = i): warning 2>
#> <number_warning in f2(i = i): warning 3>
#> [1] 4