Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify the dots argument when calling a tidyselect-using function without needing to specify the preceding arguments

Here's a simplified version of a function I have in a package that uses the ... argument and tidyselect to select variables:

# this toy function just selects the ... variables
foo <- function(dat = mtcars, ...){
  expr <- rlang::expr(c(...))
  cols_to_select <- tidyselect::eval_select(expr, data = dat)
  dplyr::select(dat, all_of(cols_to_select))
}

This works: foo(mtcars, cyl)

But my actual function has more preceding arguments before the ... argument, all with default values. It's tedious to type them all in cases where I call my function with those default values and pass a value to ... .

This is what I want - to assume dat = mtcars - but it does not work:

foo(... = cyl)

Error: Names must not be of the form ... or ..j.

Can I modify either the function or the call to allow direct specification of ... ?

like image 599
Sam Firke Avatar asked Mar 19 '20 15:03

Sam Firke


1 Answers

It is generally a good idea™ to put arguments with default values after the dots:

f <- function( ..., dat=mtcars )
    dplyr::select( dat, ... )

f(cyl)                 # Works
f(dat=iris, Species)   # Also works

If your API doesn't allow you to place named default arguments after the dots, here's another alternative. Note that you don't have to specify named arguments with default values explicitly. You can simply leave them "missing":

foo(, cyl)    # Same as foo( dat=mtcars, cyl )

If you have a lot of default arguments, and you don't want to keep putting a bunch of commas in your calls, you can make use of purrr::partial() to capture this pattern into a standalone function:

foo2 <- purrr::partial(foo, ,)  # Effectively partial(foo, dat=mtcars)
foo2(cyl)                       # Works

If that still involves typing more commas than you prefer, you can add one more step:

foo3 <- purrr::partial( foo, !!!purrr::keep(formals(foo), nzchar) )
foo3(cyl, mpg)                  # Also works
like image 168
Artem Sokolov Avatar answered Oct 19 '22 18:10

Artem Sokolov