2

I want to be able to take the ellipsis ... and use it in multiple child functions inside of a parent function. Doing so throws an error which is sensible as I am passing z to fun1 which has no z argument.

tester <- function(x, ...) {
    list(a=x, b=fun1(...), c=fun2(...))
}

fun1 <- function(y) y * 6
fun2 <- function(z) z + 1

tester(z=4, y=5, x=6)

## > tester(z=4, y=5, x=6)
## Error in fun1(...) : unused argument (z = 4)

What is the most generalizable way to use arguments from an ellipsis in multiple child functions. Pretend the problem gets worse and we have 10000 child functions each getting different arguments from .... The desired output would be:

$a
[1] 6

$b
[1] 30

$c
[1] 5

I suspect it may be useful to capture the formals of each child function and match against the named arguments in ... but that seems less generalizable (but that may be as good as it gets).

Carl Witthoft
  • 20,573
  • 9
  • 43
  • 73
Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519
  • 4
    I think a solution could be to declare your child functions with ellipses, even if they don't make use of it. For instance `fun1 <- function(y,...) y * 6` etcetera. – nicola Sep 15 '14 at 12:56
  • And already defined functions with no `...` could be redefined inside of the function. This may be the way to go. – Tyler Rinker Sep 15 '14 at 13:02
  • 1
    In this question, I ended up checking for which named parameters a child function understood before passing them along: http://stackoverflow.com/questions/25749661/how-to-pass-the-parameters-in-the-parent-function-to-its-two-children-func/25750688#25750688 – MrFlick Sep 15 '14 at 13:04

2 Answers2

1

If you can't change the input functions, you could try this:

tester <- function(x, ...) {
  args <- as.list(match.call())[-1]
  args1 <- head(names(as.list(args(fun1))), -1)
  args2 <- head(names(as.list(args(fun2))), -1)

  list(a=x, b=do.call(fun1, args[names(args) %in% args1]), 
       c=do.call(fun2, args[names(args) %in% args2]))
}

fun1 <- function(y) y * 6
fun2 <- function(z) z + 1

tester(z=4, y=5, x=6)
#$a
#[1] 6
#
#$b
#[1] 30
#
#$c
#[1] 5

It's awfully complicated and I wouldn't be surprised if you encounter dragons.

Roland
  • 127,288
  • 10
  • 191
  • 288
1

Here's @nicola's answer:

tester <- function(x, ...) {
    list(a=x, b=fun1(...), c=fun2(...), d=path.expand2(...))
}

fun1 <- function(y, ...) y * 6
fun2 <- function(z, ...) z + 1
path.expand2 <- function(path, ...) path.expand(path)

tester(z=4, y=5, x=6, path="~/thepath")

## $a
## [1] 6
## 
## $b
## [1] 30
## 
## $c
## [1] 5
## 
## $d
## [1] "C:/Users/trinker/thepath"
Tyler Rinker
  • 108,132
  • 65
  • 322
  • 519