I'm looking for a way to quote an argument passed to function (consider substitute()
, ggplot2
's aes()
, subset()
or data.table
's [
behavior), but do it conditionally - only if not already quoted with quote()
.
This is because I'd like to easily chain functions, that do not make assumptions whether an argument is previously quoted, or not - but instead substitute it as needed.
Few questions:
- Why is this a bad idea?
- Are there already any built-in methods to achieve this goal?
- The
tryCatch
part is becauseis.language
throws an error if anx
promise evaluates to a non-defined variable. Is there any other/better solution?
What I've come up with:
substitute_c <- function(x) {
e <- suppressWarnings(
tryCatch({x; FALSE},
error = function(e) TRUE))
if (e || !is.language(x)) {
substitute_q(substitute(x), env = parent.frame())
} else {
x
}
}
How it works:
require(data.table)
require(dplyr)
# Example 1
fn <- function(x) substitute_c(x)
fn2 <- function(y) fn(substitute_c(y))
fn3 <- function(z) fn2(substitute_c(z))
fn(quote(a + b)
fn(a + b)
fn2(a + b)
fn3(quote(a + b))
# Example 2
dtcars <- mtcars %>% as.data.table
subset_test <- function(dt, cols) {
cols <- substitute_c(cols)
dt[, eval(cols)]
}
subset_test2 <- function(dt, cols) {
cols <- substitute_c(cols)
subset_test(dt, cols)
}
subset_test(dtcars, .(mpg, cyl))
subset_test(dtcars, list(mpg, cyl))
subset_test2(dtcars, .(mpg, cyl))
subset_test2(dtcars, list(mpg, cyl))