Just to illustrate the problem, let's say I am writing a function that returns TRUE
if a column exists in the data frame and produces an error if it doesn't.
We can do this using stopifnot()
:
does_column_exist <- function(data, col_name) {
stopifnot("column exists" = col_name %in% colnames(data))
return(TRUE)
}
does_column_exist(mtcars, "mpg")
#> [1] TRUE
try(does_column_exist(mtcars, "mpg2"))
#> Error in does_column_exist(mtcars, "mpg2") : column exists
Created on 2023-12-03 with reprex v2.0.2
But note that the error message is vague. If I were to apply this function in a mapper, it'll be difficult to see which column doesn't exist.
To solve this, I can try to customize the name for the provided expression to contain the column name:
does_column_exist2 <- function(data, col_name) {
stopifnot(sprintf("%s column exists", col_name) = col_name %in% colnames(data))
return(TRUE)
}
But this code isn't syntactically valid (Error: unexpected '='
).
So I am wondering if there is any way to use sprintf()
in LHS of an assignment? If not, how could one customize the name for expression in stopifnot()
calls?
You cannot evaluate something on the left hand side of =
or <-
. That's also the reason why people use assign
or data.table makes use of the :=
operator.
What you can do instead? Usually do.call
comes in handy in such situations. Here, since stopifnot()
works with named arguments, setNames()
is also an option:
does_column_exist2 <- function(data, col_name) {
# setNames
stopifnot(setNames(nm = sprintf("%s column exists", col_name),
object = col_name %in% colnames(data)))
# do.call with setNames().
# bit unessecary here but do.call works in many situations in which evaluated
# arguments should be used
do.call(stopifnot, list(setNames(nm = sprintf("%s column exists", col_name),
object = col_name %in% colnames(data))))
return(TRUE)
}