How to do.call a dplyr function

My problem is the following; I need to use do.call to execute code similar to this:

do.call(dplyr::select, list(mtcars, mpg))

However this fails with following error message:

Error in do.call(dplyr::select, list(mtcars, mpg)) : 
  object 'mpg' not found

Quoting mpg works:

do.call(dplyr::select, list(mtcars, "mpg"))

mpg dbl 21 21 22.8 21.4 18.7 18.1 

That's great, but now comes the weird part. If I wrap this inside a function, nothing works:

purely <- function(.f){

  function(..., .log = "Log start..."){

    res <- tryCatch(
      do.call(.f, list(...)),
      condition = function(cnd) cnd
    )

    suppressWarnings(
      res$result <- if(all(c("message", "call") %in% names(res))){
                      NA
                    } else {
                      res
                    }
    )

    list(result = res$result,
         log = res$message)

  }
}

I wrote purely() to catch errors, warnings and messages. This works on simple functions:

purely(log)(10)

$result
[1] 2.302585

$log
NULL

and conditions get captured:

purely(log)(-10)
$result
[1] NA

$log
[1] "NaNs produced"

So if we go back to our dplyr example:

purely(select)(mtcars, mpg) 

$result
[1] NA

$log
[1] "object 'mpg' not found"

Quoting mpg, as before, does not work either:

purely(select)(mtcars, "mpg")
$result
[1] NA

$log
[1] "`scoped_bindings()` is deprecated as of rlang 0.4.2.\nPlease use `local_bindings()` instead."

I'm pretty sure this has something to do with the fact that arguments get passed down a function in the body of purely, but I can't wrap my head around it. Any ideas, help much appreciated.

Hi brodriguesco,

Quoting mpg, as before, does not work either

Apparently it works on my side:

library(dplyr)

purely <- function(.f){
  
  function(..., .log = "Log start..."){
    
    res <- tryCatch(
      do.call(.f, list(...)),
      condition = function(cnd) cnd
    )
    
    suppressWarnings(
      res$result <- if(all(c("message", "call") %in% names(res))){
        NA
      } else {
        res
      }
    )
    
    list(result = res$result,
         log = res$message)
    
  }
}


purely(select)(mtcars, "mpg")
#> $result
#>                      mpg
#> Mazda RX4           21.0
#> Mazda RX4 Wag       21.0
#> Datsun 710          22.8
#> Hornet 4 Drive      21.4
#> Hornet Sportabout   18.7
#> Valiant             18.1
#> Duster 360          14.3
#> Merc 240D           24.4
#> Merc 230            22.8
#> Merc 280            19.2
#> Merc 280C           17.8
#> ...
#>
#> $log
#> NULL

Have you tried defusing mpg? Like:

purely(select)(mtcars, expr(mpg))

#> $result
#>                      mpg
#> Mazda RX4           21.0
#> Mazda RX4 Wag       21.0
#> Datsun 710          22.8
#> Hornet 4 Drive      21.4
#> Hornet Sportabout   18.7
#> Valiant             18.1
#> Duster 360          14.3
#> Merc 240D           24.4
#> Merc 230            22.8
#> ...
#> 
#> $log
#> NULL
1 Like

Many, many thanks! Your answer pointed me towards the right direction! First of all, it was weird that when column names were quoted, it worked on your machine. This was the sign that I had to update my packages. Afterwards, I re-read the doc on defusing and changed the do.call call from:

 do.call(.f, list(...)),

to

      do.call(.f, eval(substitute(alist(...))))

doing so now works:

 purely(select)(mtcars, mpg, am, starts_with("c"))
$result
data.frame [32, 4] 
mpg  dbl 21 21 22.8 21.4 18.7 18.1
am   dbl 1 1 1 0 0 0
cyl  dbl 6 6 4 6 8 6
carb dbl 4 4 1 1 2 1 

$log
NULL


Thank you!

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.