R: Does a condition or its ancestors inherit from a class?

cnd_inherits {rlang} | R Documentation

## Does a condition or its ancestors inherit from a class?

### Description

Like any R objects, errors captured with catchers like `tryCatch()` have a `class()` which you can test with `inherits()`. However, with chained errors, the class of a captured error might be different than the error that was originally signalled. Use `cnd_inherits()` to detect whether an error or any of its parent inherits from a class.

Whereas `inherits()` tells you whether an object is a particular kind of error, `cnd_inherits()` answers the question whether an object is a particular kind of error or has been caused by such an error.

### Usage

    cnd_inherits(cnd, class)

### Arguments

`cnd` | A condition to test.
`class` | A class passed to `inherits()`.

### Capture an error with `cnd_inherits()`

Error catchers like `tryCatch()` and `try_fetch()` can only match the class of a condition, not the class of its parents. To match a class across the ancestry of an error, you'll need a bit of craftiness.

Ancestry matching can't be done with `tryCatch()` at all so you'll need to switch to `withCallingHandlers()`. Alternatively, you can use the experimental rlang function `try_fetch()` which is able to perform the roles of both `tryCatch()` and `withCallingHandlers()`.

#### `withCallingHandlers()`

Unlike `tryCatch()`, `withCallingHandlers()` does not capture an error. If you don't explicitly jump with an error or a value throw, nothing happens.

Since we don't want to throw an error, we'll throw a value using `callCC()`:

    f <- function() {
      parent <- error_cnd("bar", message = "Bar")
      abort("Foo", parent = parent)
    }

    cnd <- callCC(function(throw) {
      withCallingHandlers(
        f(),
        error = function(x) if (cnd_inherits(x, "bar")) throw(x)
      )
    })

    class(cnd)
    #> [1] "rlang_error" "error"       "condition"
    class(cnd$parent)
    #> [1] "bar"         "rlang_error" "error"       "condition"

#### `try_fetch()`

This pattern is easier with `try_fetch()`. Like `withCallingHandlers()`, it doesn't capture a matching error right away. Instead, it captures it only if the handler doesn't return a `zap()` value.

    cnd <- try_fetch(
      f(),
      error = function(x) if (cnd_inherits(x, "bar")) x else zap()
    )

    class(cnd)
    #> [1] "rlang_error" "error"       "condition"
    class(cnd$parent)
    #> [1] "bar"         "rlang_error" "error"       "condition"

[Package rlang version 1.0.2 Index]