From ?match.call
:
match.call
is most commonly used in two circumstances: […] To pass most of the call to another function […]
After reading that, I expected I could use match.call
when I want to pass all arguments of one function to another function without listing these arguments one by one.
Example: outer1
passes arguments one by one, outer2
uses match.call
.
outer1 <- function(a, b, c) {
inner1(a, b, c)
}
inner1 <- function(a, b, c) {
return(a + b + c$first + c$second)
}
outer2 <- function(a, b, c) {
mycall <- match.call()
inner2(mycall)
}
inner2 <- function(call) {
return(call$a + call$b + call$c$first + call$c$second)
}
outer1(1, 2, list(first = 3, second = 4)) # OK: 10
outer2(1, 2, list(first = 3, second = 4)) # OK: 10
The first problem arises, when -1
instead of 1
is passed to outer2
:
outer2(-1, 2, list(first = 3, second = 4)) # Error in call$a + call$b : non-numeric argument to binary operator
Question 1: What is the technical difference between passing -1
instead of 1
? I know that
typeof(quote(1)) # double
typeof(quote(-1)) # language
but I suppose that the fact that I passed a language
object in the second case is not the (only) relevant difference because passing something of type language to argument c
works (typeof(quote(list(first = 3, second = 4))) # language
).
In order to overcome the problem above, I try to eval
all arguments that are of type language
:
outer3 <- function(a, b, c) {
parsedCall <- lapply(match.call()[-1L], FUN=function(argument) {
if(is.language(argument)) {
return(eval(argument))
} else {
return(argument)
}
})
inner3(parsedCall)
}
inner3 <- function(parsedCall) {
return(parsedCall$a + parsedCall$b + parsedCall$c$first + parsedCall$c$second)
}
outer3(-1, 2, list(first = 3, second = 4)) # OK: 8
Question 2: The approach in outer3
seems to "work" but are there further pitfalls I need to take into account? (I know that in some cases it might be disadvantageous to evaluate the arguments but for my case this should not be an issue.)
Question 3: I suppose that the desire to pass all arguments to another function is not very uncommon. Is there a better/standard approach than what I did?
Question 4: Is it advantageous to pass the raw call
to the inner function an do the eval
stuff there? Would this be helpful if I would like to have the arguments as local variables in the inner
functions (instead of elements of the parsedCall
list)? Then, the body of inner3
could be identical to the body of inner1
(while with the current solution, I have to replace a+b
with parsedCall$a + parsedCall$b
).
Function Call When calling a function with a function parameter, the value passed must be a pointer to a function. Use the function's name (without parentheses) for this: func(print); would call func , passing the print function to it.
You can access specific arguments by calling their index. var add = function (num1, num2) { // returns the value of `num1` console. log(arguments[0]); // returns the value of `num2` console. log(arguments[1]); // ... };
match. call returns a call in which all of the specified arguments are specified by their full names.
arguments is an Array -like object accessible inside functions that contains the values of the arguments passed to that function.
Regarding your question:
I suppose that the desire to pass all arguments to another function is not very uncommon. Is there a better/standard approach than what I did?
Then I would say this is a more common way to pass the arguments on:
inner1 <- function(a, b, c) {
return(a + b + c$first + c$second)
}
outer3 <- function(a, b, c) {
mycall <- match.call()
mycall[[1]] <- as.symbol("inner1") # use inner 1
eval(mycall)
}
outer4 <- function(a, b, c) {
.args <- as.list(match.call()[-1])
do.call(inner1, .args)
}
outer3(-1, 2, list(first = 3, second = 4))
#R> [1] 8
outer4(-1, 2, list(first = 3, second = 4))
#R> [1] 8
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