Search code examples
rfunctionsubsetevalellipsis

Non-standard evaluation through *ellipsis* argument using the `subset` function within a second function


My goal is to transfer the subset argument to the subset function within a second function. I am able to make it work (first example below), but not when using the ellipsis to pass a named argument.

# WORKS
subset2 <- function(data, subset) {
  x <- substitute(subset)
  modified_data <- model.frame(~., data = data, subset = eval(x))
  return(modified_data)
}
subset2(mtcars, subset = cyl == 6)
#>                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
#> Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
#> Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
#> Merc 280       19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
#> Merc 280C      17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
#> Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6

# Doesn't work
subset2 <- function(data, ...) {
  dots <- list(...)
  subset <- dots$subset
  x <- substitute(subset)
  modified_data <- model.frame(~., data = data, subset = eval(x))
  return(modified_data)
}
subset2(mtcars, subset = cyl == 6)
#> Error in eval(expr, envir, enclos): object 'cyl' not found

Created on 2023-07-08 with reprex v2.0.2

Could someone shed light on why using the ellipsis breaks this example, and what can be done to fix it?

Related threads: 1, 2, 3. I also read http://adv-r.had.co.nz/Computing-on-the-language.html


Solution

  • You're probably overcomplicating things. The following should work for you:

    subset2 <- function(data, ...) {
      x <- substitute(...)
      model.frame(~., data = data, subset = eval(x, envir = data))
    }
    

    Testing, we have:

    subset2(mtcars, subset = cyl == 6)
    #>                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
    #> Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
    #> Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
    #> Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
    #> Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
    #> Merc 280       19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
    #> Merc 280C      17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
    #> Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
    

    Created on 2023-07-08 with reprex v2.0.2