How to check existence of an input argument for R functions

24,555

Solution 1

@Sacha Epskamp has a pretty good solution, but it doesn't always work. The case where it fails is if the "z" argument is passed in as NULL...

# Sacha's solution
myFun <- function(x, y, ...) { 
  args <- list(...)
  exist <- !is.null(args[['z']])
  return(exist)
}

myFun(x=3, z=NULL) # FALSE, but should be TRUE!


# My variant
myFun2 <- function(x, y, ...) {
  args <- list(...)
  exist <- "z" %in% names(args)
  exist
}

myFun2(x=3, z=NULL) # TRUE

Solution 2

I think you're simply looking for hasArg

myFun <- function(x, y, ...) { 
  hasArg(z)
}

> myFun(x=3, z=NULL)
[1] TRUE

From ?hasArg:

The expression hasArg(x), for example, is similar to !missing(x), with two exceptions. First, hasArg will look for an argument named x in the call if x is not a formal argument to the calling function, but ... is. Second, hasArg never generates an error if given a name as an argument, whereas missing(x) generates an error if x is not a formal argument.

Solution 3

There might be instances when you might not want to call list(...), since this will evaluate all the expressions in the dots. For example,

myFun <- function(x, y, ...){
  myArgs <- list(...)
  zInArgs <- ("z" %in% names(myArgs))
  return(zInArgs)
}

myFun(x = 2, y = "Happy", z = list(rep(rnorm(2e6), 100)))

This will take a long time. Instead, use match.call():

myFun <- function(x, y, ...){
  myArgs <- match.call()
  zInArgs <- ("z" %in% names(myArgs))
  return(zInArgs)
}

myFun(x = 2, y = "Happy", z = list(rep(rnorm(2e6), 100)))

The first example is still chugging away on my machine, while the second example should take practically no time at all.

EDIT:

To answer the comment from @CarlWitthoft:

R> system.time(
+   (myAns <- myFun(x = 2, y = "Happy", z = list(rep(rnorm(2e6), 100))))
+ )
   user  system elapsed 
      0       0       0 
R> myAns
[1] TRUE

Solution 4

Here is a way I often do it. First convert ... to a list, then check if the elements are not NULL:

myFun <- function(x, y, ...) { 
args <- list(...)
exist <- !is.null(args[['z']])
return(exist)
}

Some results:

> myFun()
[1] FALSE
> myFun(z=1)
[1] TRUE
Share:
24,555
danioyuan
Author by

danioyuan

Serious R user. Statistician. Also use Python, C, C++, PHP, Javascript, SQL.

Updated on July 16, 2022

Comments

  • danioyuan
    danioyuan almost 2 years

    I have a function defined as

    myFun <- function(x, y, ...) {
      # using exists
      if (exists("z")) { print("exists z!") }
      # using missing
      try(if (!missing("z")) { print("z is not missing!") }, silent = TRUE)
      # using get
      try(if (get("z")) { print("get z!") }, silent = TRUE)
    
      # anotherFun(...)
    }
    

    In this function, I want to check whether user input "z" in the argument list. How can I do that? I tried exists("z"), missing("z"), and get("z") and none of them works.

    • joran
      joran over 12 years
      Can you show exactly how you've used missing? Because AFAIK that's the correct function to use.
    • Joshua Ulrich
      Joshua Ulrich over 12 years
      It would help if you provide a bit more context. There may be a better way to do what you're trying to accomplish.
    • Sacha Epskamp
      Sacha Epskamp over 12 years
      @joran, missing() only applies for argument. Here there is no argument z, it can only be entered as part of ...
    • joran
      joran over 12 years
      @SachaEpskamp I agree. I simply wasn't sure if what the OP wrote was actually what they were doing.
    • danioyuan
      danioyuan over 12 years
      I've modified the code in the question to make it easier to understand. Thanks for the comments.
  • Sacha Epskamp
    Sacha Epskamp over 12 years
    I don't think this is the intended way ... is supposed to be used though. It is more a way of passing arguments to another function, but this is how I currently use it in my package as well (I really should change that:))
  • danioyuan
    danioyuan over 12 years
    Sacha, I do agree with you. If "z" is used in this function, it should not be in the ... But very often code is already written and making one change in the argument list can introduce errors that requires many changes to fix. So this is my lazy way to make it work. :)
  • Tommy
    Tommy over 12 years
    I added an alternative solution that also handles myFun(z=NULL)
  • Sacha Epskamp
    Sacha Epskamp over 12 years
    @danioyuan Also this gives you awesome hidden and undocumented arguments that only you know about!
  • Carl Witthoft
    Carl Witthoft over 12 years
    @danioyuan: the safe, and possibly "proper," way to add an argument is to place it last in the list with a default value assigned, i.e. myfunc(x,y,...) becomes myfunc(x,y,z=1,...) . AFAIK that will provide full back-compatibility.
  • Carl Witthoft
    Carl Witthoft over 12 years
    For completeness' sake, can you report on the time it does take to run the second example?
  • BenBarnes
    BenBarnes over 12 years
    Hi @CarlWitthoft, please see my edit above. Do you get differing results?
  • Carl Witthoft
    Carl Witthoft over 12 years
    well, I get NULL for a result because I'm not allowed (yet) to install R at work :-(. So, thanks for doing the timing tests.