rio icon indicating copy to clipboard operation
rio copied to clipboard

Using an existing function for filtering `...` instead of writing it out each time.

Open bokov opened this issue 6 years ago • 8 comments

I'm watching a series of related issues and PRs here re: ....

The tidyverse/r-lib packages are using the ellipsis package for similar functionality, in case that holds any interest. Yes, it would be a dependency. But it would also eliminate the need to grow your own solution here. YMMV 🤷‍♀️

Originally posted by @jennybc in https://github.com/leeper/rio/pull/225#issuecomment-534315342

bokov avatar Sep 25 '19 19:09 bokov

I'm watching a series of related issues and PRs here re: ....

The tidyverse/r-lib packages are using the ellipsis package for similar functionality, in case that holds any interest. Yes, it would be a dependency. But it would also eliminate the need to grow your own solution here. YMMV woman_shrugging

Thank you, this is a helpful package. I don't see a way to have it actually filter out unused arguments in order to prevent an error, though. This got me thinking, though-- you're right, we can't be the first people encountering the problem of ... being passed to a function which doesn't have ... as a formal argument. In fact, Hadley Wickham had this question back in 2008 and he didn't want to reinvent the wheel by implementing it himself. After some more digging I found R.utils::doCall which does exactly what we need except that it drops argument silently.

I submitted an issue to that repo and if feedback is favorable I will submit a pull request to them which implements warnings as an option.

As you kind of alluded, we don't know how @leeper will feel about adding another dependency just for this. But if so, many of the .import.rio_* methods could follow a very consistent pattern...

Instead of

.import.rio_ods <- function(file, which = 1, header = TRUE, ...) {
    requireNamespace("readODS")
    readODS::read_ods(path = file, sheet = which, col_names = header, ...)
}

we would have this...

.import.rio_ods <- function(file, which = 1, header = TRUE, ...) {
    requireNamespace("readODS")
    a <- list(...)
    a[c('path', 'sheet', 'col_names')] <- c(file, which, header)
    doCall(readODS::read_ods, a)
}

...and for many cases the only things different from one underlying import function to another are the names of values in a that get created/overwritten and the function object.

bokov avatar Sep 25 '19 19:09 bokov

Thank you, this is a helpful package. I don't see a way to have it actually filter out unused arguments in order to prevent an error, though.

I think the ellipsis mentality is that we usually want to error for unused arguments. If you provided foreign arguments to a function that did not have ..., you'd get an error. So often a user would like to know that some of their arguments are being quietly sent to /dev/null.

However, sometimes this is necessary. That recently came up in devtools (https://www.tidyverse.org/articles/2019/09/devtools-2-2-1/#ellipsis), which lead to more flexibility being built into ellipsis (https://github.com/r-lib/ellipsis/commit/dc23a8c7b8cf644157dad5e67d078ee9d4ac64b6).

jennybc avatar Sep 27 '19 00:09 jennybc

So this is related to #132. Basically, we need:

  • a schema that provides "standard" argument names that we will use for common behavior
  • something like the crosswalk you created @bokov that maps function/package argument naming schemes to the rio standard
  • a function that takes argument lists and translates them from rio standard to package standard where appropriate, passing forward anything else, and erroring on invalid arguments

I think there's a slight annoyance that we can't use do.call() with suggested packages as the function name isn't found, ex:

> requireNamespace("data.table")
Loading required namespace: data.table
> do.call("fread", list("foo.csv"))
Error in fread("foo.csv") : could not find function "fread"
> do.call("data.table::fread", list("foo.csv"))
Error in `data.table::fread`("foo.csv") :
  could not find function "data.table::fread"

leeper avatar Dec 20 '19 19:12 leeper

Actually, it looks like that might be solvable with:

do.call(getFromNamespace("fread", "data.table"), list("foo.csv"))

https://r.789695.n4.nabble.com/do-call-method-within-namespace-td797206.html

leeper avatar Dec 20 '19 19:12 leeper

So this is related to #132.

Yes, and also #245. Actually have some code in a branch for that.

bokov avatar Dec 20 '19 19:12 bokov

Actually, it looks like that might be solvable with:

do.call(getFromNamespace("fread", "data.table"), list("foo.csv"))

https://r.789695.n4.nabble.com/do-call-method-within-namespace-td797206.html

Cooool! I learned something new today, thank you.

bokov avatar Dec 20 '19 19:12 bokov

So did I!

leeper avatar Dec 20 '19 19:12 leeper

Might this also be closed by #251 ?

bokov avatar Mar 08 '21 21:03 bokov