Skip to content

Feature request: classed errors for specific tidyselect errors #351

@yjunechoe

Description

@yjunechoe

A user's attempt at selecting a column can fail for various reasons - currently, there are some (extremely brittle) ways to infer what went wrong.

Briefly, if we wanted to distinguish between these three types of tidyselect errors (mismatch, other evaluation error, empty):

library(rlang)
library(tidyselect)
df <- data.frame(x = 1)

selectors <- exprs(
  mismatch = z,
  error = stop(),
  empty = 
)

We know that a mismatch error is classed with a vctrs subscript oob error (as of the most recent update) and also stores the problematic selection in $i:

err_mismatch <- catch_cnd(
  eval_select(selectors$mismatch, df)
)
class(err_mismatch)
#> [1] "vctrs_error_subscript_oob" "vctrs_error_subscript"    
#> [3] "rlang_error"               "error"                    
#> [5] "condition"
err_mismatch$parent
#> NULL
err_mismatch$i
#> [1] "z"

An error from evaluating the user-supplied expression gets chained, so these errors are distinguished by having a $parent:

err_error <- catch_cnd(
  eval_select(selectors$error, df)
)
class(err_error)
#> [1] "rlang_error" "error"       "condition"
err_error$parent
#> <simpleError in eval_tidy(as_quosure(expr, env), context_mask): >
err_error$i
#> NULL

Lastly, an empty selection that's promoted to an error with allow_empty = FALSE has neither $i nor a $parent:

err_empty <- catch_cnd(
  eval_select(selectors$empty, df, allow_empty = FALSE)
)
class(err_empty)
#> [1] "rlang_error" "error"       "condition"
err_empty$parent
#> NULL
err_empty$i
#> NULL

I fully acknowledge that these are not part of the official API, so I do not mean to build on top of this pattern. Instead, I was hoping that tidyselect could throw more specific, classed errors, where possible. For example, it'd be nice for an empty selection error with allow_empty = FALSE to look something like this:

err_empty2 <- catch_cnd(
  eval_select(selectors$empty, df, allow_empty = FALSE)
)
class(err_empty2)
#> [1] "tidyselect_error_disallow_empty" "rlang_error"                    
#> [3] "error"                           "condition"

... by adding the "tidyselect_error_*" class where the error gets thrown:

tidyselect/R/eval-walk.R

Lines 128 to 132 in fd22cc1

check_empty <- function(x, allow_empty = TRUE, call = caller_env()) {
if (!allow_empty && length(x) == 0) {
cli::cli_abort("Must select at least one item.", call = call)
}
}

I realize that this is a non-trivial ask that probably requires a lot of deliberation, but I was curious whether this is within scope / planned to be worked on. Thanks in advance for considering!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions