3

This question may sound silly for the toy example I provide but it actually make sense in the real situation I'm facing.

Assume function f such as:

f <- function(x) {
    if (missing(x)) 
        "something very nice happens if x is missing" 
    else 
        "something else that is also very nice happens if x not missing"
}

Sometimes I need to call f just as f() but sometimes with specified arguments.

One way to do it (based on some condition cond):

if (cond) f(1) else f()

But such construction will grow in complexity (like a cartesian product) with the need of additional arguments. I would therefore like to call f this way:

f(if (cond) 1 else *)

where * is supposed to be "nothing".

If I were the owner of f I could rewrite it as:

 f <- function(x = NULL) {
    if (null(x)) 
        "something very nice happens if x is null" 
    else 
        "something else that is also very nice happens if x not null"
}

and use * = NULL. Unfortunately I can not do this so another way would be much appreciated!

P.S. This is my first question on StackOverflow :-) D.S.

2 Answers2

2

You could use do.call with an alist:

f <- function(x, y) {
  if (missing(x)) 
    "something very nice happens if x is missing" 
  else 
    "something else that is also very nice happens if x not missing"
}

helper <- function(x = NULL, y) {
  args <- alist(x = , y = y)
  if (!is.null(x)) args[["x"]] <- x
  do.call(f, args)
}

helper(1, 1)
#[1] "something else that is also very nice happens if x not missing"
helper(NULL, 1)
#[1] "something very nice happens if x is missing"
helper(if (1 > 2) 3, 1)
#[1] "something very nice happens if x is missing"
Roland
  • 127,288
  • 10
  • 191
  • 288
0

Following @Roland's lead, I would do...

helper <- function(f, ..., ifmissing=NULL){
    lacked <- setdiff(names(formals(f)), names(list(...)))
    wanted <- names(ifmissing)

    missed <- intersect(lacked,wanted)    
    if (length(missed)){
        ifmissing[[ missed[1] ]]
    } else {
        f(...)
    }
}

Here is an example. g is a function you cannot modify, but you have a list of actions to follow when each of its arguments is missing. The first argument missing (if any) determines the value returned.

g <- function(x,y) x^y

helper_g <- function(...){
    cond <- list(
        x = "d'oh, base is missing",
        y = "gah, exponent is missing"
    )
    helper(g, ..., ifmissing=cond)
}

helper_g(x=2,y=3) # 8
helper_g(y=3)     # "d'oh, base is missing"
helper_g(x=2)     # "gah, exponent is missing"
helper_g()        # "d'oh, base is missing"

(I realize this isn't exactly the same problem the OP is facing, where f already has internal rules for handling missing arguments.)

Frank
  • 66,179
  • 8
  • 96
  • 180