with_handlers {rlang} | R Documentation |
Condition handlers are functions established on the evaluation
stack (see ctxt_stack()
) that are called by R when a condition is
signalled (see cnd_signal()
and abort()
for two common signal
functions). They come in two types: exiting handlers, which jump
out of the signalling context and are transferred to
with_handlers()
before being executed. And inplace handlers,
which are executed within the signal functions.
with_handlers(.expr, ...)
.expr |
An expression to execute in a context where new handlers are established. The underscored version takes a quoted expression or a quoted formula. |
... |
Named handlers. Handlers should inherit from |
An exiting handler is taking charge of the condition. No other
handler on the stack gets a chance to handle the condition. The
handler is executed and with_handlers()
returns the return value
of that handler. On the other hand, in place handlers do not
necessarily take charge. If they return normally, they decline to
handle the condition, and R looks for other handlers established on
the evaluation stack. Only by jumping to an earlier call frame can
an inplace handler take charge of the condition and stop the
signalling process. Sometimes, a muffling restart has been
established for the purpose of jumping out of the signalling
function but not out of the context where the condition was
signalled, which allows execution to resume normally. See
rst_muffle()
the muffle
argument of inplace()
and the
mufflable
argument of cnd_signal()
.
Exiting handlers are established first by with_handlers()
, and in
place handlers are installed in second place. The latter handlers
thus take precedence over the former.
# Signal a condition with cnd_signal(): fn <- function() { g() cat("called?\n") "fn() return value" } g <- function() { h() cat("called?\n") } h <- function() { cnd_signal("foo") cat("called?\n") } # Exiting handlers jump to with_handlers() before being # executed. Their return value is handed over: handler <- function(c) "handler return value" with_handlers(fn(), foo = exiting(handler)) # In place handlers are called in turn and their return value is # ignored. Returning just means they are declining to take charge of # the condition. However, they can produce side-effects such as # displaying a message: some_handler <- function(c) cat("some handler!\n") other_handler <- function(c) cat("other handler!\n") with_handlers(fn(), foo = inplace(some_handler), foo = inplace(other_handler)) # If an in place handler jumps to an earlier context, it takes # charge of the condition and no other handler gets a chance to # deal with it. The canonical way of transferring control is by # jumping to a restart. See with_restarts() and restarting() # documentation for more on this: exiting_handler <- function(c) rst_jump("rst_foo") fn2 <- function() { with_restarts(g(), rst_foo = function() "restart value") } with_handlers(fn2(), foo = inplace(exiting_handler), foo = inplace(other_handler))