1

I would like to write a wrapper function for two functions that take optional arguments.

Here is an example of a function fun to wrap funA and funB

funA <- function(x = 1, y = 1) return(x+y)
funB <- function(z = c(1, 1) return(sum(z))

fun <- function(x, y, z)

I would like fun to return x+y if x and y are provided, and sum(z) if a vector z is provided.

I have tried to see how the lm function takes such optional arguments, but it is not clear exactly how, e.g., match.call is being used here.

After finding related questions (e.g. How to use R's ellipsis feature when writing your own function? and using substitute to get argument name with )), I have come up with a workable solution.

My solution has just been to use

fun <- function(...){
  inputs <- list(...)
  if (all(c("x", "y") %in% inputs){
    ans <- funA(x, y)
   } else if ("z" %in% inputs){
    ans <- funB(z)
   }

Is there a better way?

Note: Perhaps this question can be closed as a duplicate, but hopefully it can serve a purpose in guiding other users to a good solution: it would have been helpful to have expanded my search to variously include ellipsis, substitute, in addition to match.call.

Community
  • 1
  • 1
David LeBauer
  • 31,011
  • 31
  • 115
  • 189

2 Answers2

4

Use missing. This returns funA(x, y) if both x and y are provided and returns funB if they are not but z is provided and if none of them are provided it returns NULL:

fun <- function(x, y, z) {
          if (!missing(x) && !missing(y)) {
             funA(x, y) 
          } 
          else if (!missing(z))  {
             funB(z)
          }

This seems to answer your question as stated but note that the default arguments in funA and funB are never used so perhaps you really wanted something different?

Note the fun that is provided in the question only works if the arguments are named whereas the fun here works even if they are provided positionally.

Ricardo Guerreiro
  • 497
  • 1
  • 4
  • 17
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • I don't want to use the defaults necessarily, I just put them in for illustration (e.g. that one function takes two numbers, the other a vector) – David LeBauer Oct 08 '13 at 21:46
2

I would something like for example this using match.call. This is similar to your solution but more robust.

fun <- function(...){
  arg <- as.list(match.call())[-1]
  f <- ifelse(length(arg)>1,"funA","funB")
  do.call(f,arg)
}

fun(x=1,y=2) ## or fun(1,2) no need to give named arguments
[1] 3
> fun(z=1:10) ## fun(1:10)
[1] 55
agstudy
  • 119,832
  • 17
  • 199
  • 261