How to check existence of an input argument for R functions
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
danioyuan
Serious R user. Statistician. Also use Python, C, C++, PHP, Javascript, SQL.
Updated on July 16, 2022Comments
-
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")
, andget("z")
and none of them works.-
joran over 12 yearsCan you show exactly how you've used
missing
? Because AFAIK that's the correct function to use. -
Joshua Ulrich over 12 yearsIt 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 over 12 years@joran,
missing()
only applies for argument. Here there is no argumentz
, it can only be entered as part of...
-
joran over 12 years@SachaEpskamp I agree. I simply wasn't sure if what the OP wrote was actually what they were doing.
-
danioyuan over 12 yearsI've modified the code in the question to make it easier to understand. Thanks for the comments.
-
-
Sacha Epskamp over 12 yearsI 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 over 12 yearsSacha, 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 over 12 yearsI added an alternative solution that also handles
myFun(z=NULL)
-
Sacha Epskamp over 12 years@danioyuan Also this gives you awesome hidden and undocumented arguments that only you know about!
-
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,...)
becomesmyfunc(x,y,z=1,...)
. AFAIK that will provide full back-compatibility. -
Carl Witthoft over 12 yearsFor completeness' sake, can you report on the time it does take to run the second example?
-
BenBarnes over 12 yearsHi @CarlWitthoft, please see my edit above. Do you get differing results?
-
Carl Witthoft over 12 yearswell, I get NULL for a result because I'm not allowed (yet) to install R at work :-(. So, thanks for doing the timing tests.