Working with dot-dot-dot has been a challenge.
I would not have understood this post by Gabor Grothenieck in r-help on 2011-10-9, but I do now! And I'm so happy!
Suppose we wish to call f with the control.list components plus
those in the default.args not already specified in the control.list.
If any such arg is not an arg of f exclude it:
# test data - f, default.args and control.list
f < - function(a, b, c = 0, d = 1) print(match.call()) default.args <- list(a = 2, b = 1) control.list <- list(a = 1, d = 2, e = 3) # override default.args with control.list use.args <- modifyList(default.args, control.list) # exclude components of use.args that are not args of f sel <- names(use.args) %in% names(as.list(args(f))) final.args <- use.args[sel] # run f do.call("f", final.args) The last line gives: > do.call("f", final.args)
f(a = 1, b = 1, d = 2)
Wow. That touches all the bases. Understand that, you understand "it".
The problem I fought first was the "double specification" of options. The ... may add arguments that are already set. The magic bullet for that is the "modifyList" function, which can take a default list of settings and selectively replace them with new settings. Awesome.
Then you have the problem that the dot arguments may not apply to a function in which they are to be called. That's where the args function retrieves the legal arguments from a function and then picks the ones that match. Awesome.
I used "formals" for same purpose in my code, before I saw Gabor's post.
f <- function(x, ...)
dots <- list(...) #1
if(length(dots) == 0) return(NULL)
cat("The arguments in ... are\n")
The function, f, stores all but the first input argument in the ellipsis variable. For accessing its contents, it is easiest to convert it to a list (1). The main use however is for passing arguments to subfunctions, which requires no conversion (2).
input_list <- list(...)
and other times:
object <- as.list(substitute(list(...)))[-1L]