I'm writing a function that accepts a variable number of arguments. Moreover, I would like the user to be able to leave some of these arguments as missing.
Consider just the task of turning the ... into a list of arguments. Here is my first attempt:
f <- function(...) list(...)
This fails:
f(1,,2)
## Error in f(1, , 2) : argument is missing, with no default
I would like the result to be list(1, NULL, 2). (I am not worried about distinguishing f(1,,2) from f(1,NULL,2).)
Here is my second attempt:
g <- function(...)
{
args <- match.call()
miss <- vapply(args, identical, NA, quote(expr=))
args[miss] <- list(NULL)
args[[1L]] <- quote(list)
eval.parent(args)
}
This works (sort of):
identical(g(1,,2), list(1, NULL, 2))
## [1] TRUE
However, it fails when forwarding dots:
gg <- function(...) g(...)
identical(gg(1,,2), list(1,NULL,2))
## [1] FALSE
Is there a way to achieve the same results as g, but in a way that allows forwarding dots and without using match.call()?
Edit: Issues with forwarding dots.
It's tempting to try the following:
h <- function(...)
{
args <- substitute(list(...))
miss <- vapply(args, identical, NA, quote(expr=))
args[miss] <- list(NULL)
eval.parent(args)
}
However, as @lionel points out, there will be issues if you try to forward ... from another function:
hh <- function(...) h(letters, ...)
local({ a <- "foo"; h(a) })
## Error in eval(expr, p) : object 'a' not found
It seems like you either need the expand.dots functionality of match.call, or you need to use a quosure (from the rlang package).