13

I want to call a function but depending on the situation I might call it with extra arguments or not. Here is a simple example:

FUN <- function(arg1 = "default1", arg2 = "default2", arg3 = "default3")
          print(list(arg1, arg2, arg3))


x1 <- "hi"
x2 <- TRUE
x3 <- 1:3

use.arg3 <- FALSE   # This will decide if `x3` is used or not.

if (use.arg3) {
   FUN(arg1 = x1, arg2 = x2, arg3 = x3)
} else {
   FUN(arg1 = x1, arg2 = x2)
}

While the code is clear, it feels a little redundant. Also imagine that if I had similar use.arg1 and use.arg2 variables, I would have an ugly mix of possibilities (8)...

I have a solution posted below but I find it a little complicated, to the point that I always struggle to remember the exact syntax.

If you have a better idea, thank you for sharing.

flodel
  • 87,577
  • 21
  • 185
  • 223

2 Answers2

18

One solution is to use do.call after building a list with the proper arguments:

do.call(FUN, c(list(arg1 = x1, arg2 = x2),   # unconditional args
               list(arg3 = x3)[use.arg3]))   # conditional arg

And it generalizes well to multiple conditions:

do.call(FUN, c(list(arg1 = x1)[use.arg1]     # conditional arg
               list(arg2 = x2)[use.arg2]     # conditional arg
               list(arg3 = x3)[use.arg3]))   # conditional arg
flodel
  • 87,577
  • 21
  • 185
  • 223
  • 3
    Why not combine them, i.e. `do.call(FUN,list(arg1=x1,arg2=x2,arg3=x3)[c(use.arg1,use.arg2,use.arg3)])` Or, what I would do, make a vector `use.args <- rep(TRUE,3)` and set to FALSE whatever argument I don't want to use, which gives `do.call(FUN,list(arg1=x1,arg2=x2,arg3=x3)[use.args])`. Other possibilities (use of `...` etc.) depends on the actual case, but this is the most generic answer. – Joris Meys Dec 21 '12 at 15:06
  • I feel like I sometimes see people use a construction like `FUN(arg1 = x1, arg2 = x2, arg3 = if(use.arg3) x3 else NULL)` but I'm not sure how advisable that is. – joran Dec 21 '12 at 15:09
  • @joran, in case `use.arg3` is `FALSE`, `NULL` will be used for `arg3` instead of `FUN`'s default value if it has one. – flodel Dec 21 '12 at 15:12
  • @flodel How you define FUN here? FUN <- function(arg1,arg2,arg3){..} will fail if use.arg3 <- FALSE, isn'it? – agstudy Dec 21 '12 at 18:35
9

Continuing the discussion from the comments on flodel's answer, here's an extension of my idea, out of curiosity. Not sure if it's really a feasible option:

FUN(arg1 = x1, arg2 = x2, arg3 = if(use.arg3) x3 else formals(FUN)$arg3)
joran
  • 169,992
  • 32
  • 429
  • 468