Split up `...` arguments and distribute to multiple functions

Separate Lists If you really want to pass different sets of parameters to different functions then it's probably cleaner to specify separate lists:

foo <- function(x, y, sum = list(), grep = list()) {
 list(sum = do.call("sum", c(x, sum)), grep = do.call("grep", c("abc", y, grep)))
}

# test

X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, sum = list(na.rm = TRUE), grep = list(value = TRUE))

## $sum
## [1] 55
## 
## $grep
## [1] "xyzabcxyz"

Hybrid list / ... An alternative is that we could use ... for one of these and then specify the other as a list, particularly in the case that one of them is frequently used and the other is infrequently used. The frequently used one would be passed via ... and the infrequently used via a list. e.g.

foo <- function(x, y, sum = list(), ...) {
 list(sum = do.call("sum", c(x, sum)), grep = grep("abc", y, ...))
}

foo(X, Y, sum = list(na.rm = TRUE), value = TRUE)

Here are a couple of examples of the hybrid approach from R itself:

i) The mapply function takes that approach using both ... and a MoreArgs list:

> args(mapply)
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) 
NULL

ii) nls also takes this approach using both ... and the control list:

> args(nls)
function (formula, data = parent.frame(), start, control = nls.control(), 
    algorithm = c("default", "plinear", "port"), trace = FALSE, 
    subset, weights, na.action, model = FALSE, lower = -Inf, 
    upper = Inf, ...) 
NULL

  1. Why does grep error before sum?

    See that sum is a lot more accommodating with its arguments:

    X <- c(1:5, NA, 6:10)
    sum(X, na.rm = TRUE, value = TRUE)
    ## [1] 56
    

    It doesn't failed because it doesn't care about other named arguments, so the value = TRUE simplifies to just TRUE which sums to 1. Incidentally:

    sum(X, na.rm = TRUE)
    ## [1] 55
    
  2. How to split ... to different functions?

    One method (that is very prone to error) is to look for the args for the target functions. For instance:

    foo <- function(x, y, ...){
        argnames <- names(list(...))
        sumargs <- intersect(argnames, names(as.list(args(sum))))
        grepargs <- intersect(argnames, names(as.list(args(grep))))
        list(sum = do.call(sum, c(list(x), list(...)[sumargs])),
             grep = do.call(grep, c(list("abc", y), list(...)[grepargs])))
    }
    

    This is prone to error anytime the arguments a function uses are not properly reported by args, such as S3 objects. As an example:

    names(as.list(args(plot)))
    ## [1] "x"   "y"   "..." ""   
    names(as.list(args(plot.default)))
    ##  [1] "x"           "y"           "type"        "xlim"        "ylim"       
    ##  [6] "log"         "main"        "sub"         "xlab"        "ylab"       
    ## [11] "ann"         "axes"        "frame.plot"  "panel.first" "panel.last" 
    ## [16] "asp"         "..."         ""           
    

    In this case, you could substitute the appropriate S3 function. Because of this, I don't have a generalized solution for this (though I don't know that it does or does not exist).