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 aborts all code currently run between `with_handlers()` and the point where the condition has been raised. `with_handlers()` passes the return value of the handler to its caller.

- Calling handlers, which are executed from inside the signalling functions. Their return values are ignored, only their side effects matters. Valid side effects are writing a log message, or jumping out of the signalling context by invoking a restart or using `return_from()`. If the raised condition was an error, this interrupts the aborting process.

  If a calling handler returns normally, it effectively declines to handle the condition and other handlers on the stack (calling or exiting) are given a chance to handle the condition.

Handlers are exiting by default, use `calling()` to create a calling handler.

### Usage

    with_handlers(.expr, ...)

    calling(handler)

### 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.
`...` | <dynamic> Named handlers. These should be functions of one argument, or formula functions. The handlers are considered exiting by default, use `calling()` to specify a calling handler.
`handler` | A handler function that takes a condition as argument. This is passed to `as_function()` and can thus be a formula describing a lambda function.

### Life cycle

`exiting()` is soft-deprecated as of rlang 0.4.0 because `with_handlers()` now treats handlers as exiting by default.

### 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 = handler)

    # Calling 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 a calling 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.4.3 Index]