I’ve learned that it’s common practice to use optional arguments in function and check them with missing() (e.g. as discussed in SO 22024082)
In this example round0 is the optional argument (I know, round0 could be defined as logical).
foo = function(a, round0) {
a = a * pi
if(!missing(round0)) round(a)
else a
}
But what if I call this function from another function, how can I pass “missing”?
bar = function(b) {
if(b > 10) round1=T
foo(b, round1)
}
If b < 10 then round1 in bar() is not defined, but is passed to foo anyway. If I modify foo():
foo = function(a, round0) {
a = a * pi
print(missing(round0))
print(round0)
if(!missing(round0)) round(a)
else a
}
and run bar(9) the output is:
bar(9)
[1] FALSE
Error in print(round0) : object 'round1' not found
Called from: print(round0)
That means: round0 is not missing, but can’t be accessed either?
I don’t want to use different function calls in bar(), if there are several optional arguments in foo(), I would have to write a function call for every missing/not missing - combination of all optional arguments.
Is it possible to pass "missing", or what other solution would apply for this problem?
In your example, round0 isn't missing, it's set to round1
which is undefined (as opposed to missing).
The best way in general of doing this is to use a default value, in your case FALSE
:
foo = function(a, round0 = FALSE) {
a = a * pi
if (!round0) round(a)
else a
}
bar = function(b) {
round1 <- FALSE
if (b > 10) round1=TRUE
foo(b, round1)
}
or where the default value cannot easily be expressed in the parameter list:
foo = function(a, round0 = NULL) {
a = a * pi
if(!is.null(round0)) round(a)
else a
}
bar = function(b) {
round1 <- NULL
if (b > 10) round1=TRUE
foo(b, round1)
}
Note in both cases you need to set the parameter to be the default value manually in your calling function.
You could also call your foo
function with or without an argument if needed within your if
statement:
bar = function(b) {
if (b > 10) foo(b, TRUE) else foo(b)
}
An alternative approach that shows how to generate a missing value is shown by @moody_mudskipper’s answer.
I recently encountered a similar problem and wanted to solve it in a general way. I think it can be done as shown in the definition of the function g()
below:
f <- function(a = 5, b = 3, c = 2, d = 7) {
if (missing(a)) {print("a is missing.")}
if (missing(b)) {print("b is missing.")}
if (missing(c)) {print("c is missing.")}
if (missing(d)) {print("d is missing.")}
cat(a, b, c, d)
}
g <- function(a = 1, b = 1, c = 1, d = 1) {
args <- as.list(match.call())
args[[1]] <- NULL # remove first list element, it's the function call
do.call(f, args, envir = parent.frame())
}
Here is what we get when calling g()
with different sets of arguments:
> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
5 3 2 7
> g(a = 3)
[1] "b is missing."
[1] "c is missing."
[1] "d is missing."
3 3 2 7
> g(b = 10, c = 10)
[1] "a is missing."
[1] "d is missing."
5 10 10 7
You can add to or remove from the args
list if you don't want to hand all arguments to the next function or want to add some. As an example, see the following function g()
that does this in a general way:
g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1) {
f_args <- c("a", "b", "c") # arguments we want to hand off to function f
# obtain the list of arguments provided
args <- as.list(match.call())
# remove first list element, it's the function call
args[[1]] <- NULL
# remove the arguments that are not listed in f_args
args <- args[na.omit(match(f_args, names(args)))]
# now add argument d, we always want it to be 0:
args <- c(args, list(d = 0))
do.call(f, args, envir = parent.frame())
}
Here is what we get when calling g()
with different sets of arguments:
> g()
[1] "a is missing."
[1] "b is missing."
[1] "c is missing."
5 3 2 0
> g(a = 3)
[1] "b is missing."
[1] "c is missing."
3 3 2 0
> g(b = 10, c = 10)
[1] "a is missing."
5 10 10 0
See this answer for additional information on do.call()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With