R: Establish handlers on the stack

with_handlers {rlang} | R Documentation

## Establish handlers on the stack

### Description

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 calling handlers, which are executed within the signal functions.

### Usage

    with_handlers(.expr, ...)

### Arguments

`.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. These should be functions of one argument. These handlers are treated as exiting by default. Use `calling()` to specify a calling handler. These dots support tidy dots features and are passed to `as_function()` to enable the formula shortcut for lambda functions.

### Details

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 a calling 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 `cnd_muffle()` 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.

### See Also

`exiting()`, `calling()`.

### Examples

    # Signal a condition with signal():
    fn <- function() {
      g()
      cat("called?\n")
      "fn() return value"
    }
    g <- function() {
      h()
      cat("called?\n")
    }
    h <- function() {
      signal("A foobar condition occurred", "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))

    # Handlers are exiting by default so you can omit the adjective:
    with_handlers(fn(), foo = 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 = calling(some_handler), foo = calling(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 = calling(exiting_handler), foo = calling(other_handler))

[Package rlang version 0.3.2 Index]