say I have a function from an R package which I want to wrap in a closure for convenience and better code readability. For simplicity, let's assume the function looks as follows:
fun <- function(text) {
as.character(substitute(text))
}
When I call that function from the console, e.g.
fun(text = "bar")
the returned value is "bar"
, which in my case is the desired behavior. The reason the function is written the way it is, is that in case I call
fun(text = bar)
the output is also "bar"
. Just for context. I obviously didn't write this function by myself, I just want to use it.
The problem: When I call fun
from within a function, like e.g.
fun2 <- function(foo) {
fun(text = foo)
}
fun2(foo = "bar")
the output will always be "foo"
instead of "bar", regardless of what I assign to foo
in the call to fun2
. Ofc I know this is how substitute()
is intended to work, but this makes it impossible (or at least very nasty?), to programmatically work with the function fun
.
My Question: Is there a way to achieve the desired behavior without rewriting fun
?
Thanks a lot in advance :)
CodePudding user response:
You could construct the call inside fun2
and evaluate it:
fun2 <- function(foo) {
eval(call("fun", foo))
}
fun2(foo = "bar")
#> [1] "bar"
The problem here is that it now no longer works if you pass bar
unquoted:
fun2(foo = bar)
#> Error in eval(call("fun", foo)) : object 'bar' not found
So you would need something like:
fun2 <- function(foo) {
if(exists(as.character(substitute(foo)), parent.frame())) {
eval(call("fun", foo))
} else {
eval(call("fun", as.character(substitute(foo))))
}
}
Which now works either way:
fun2(foo = "bar")
#> [1] "bar"
fun2(foo = bar)
#> [1] "bar"
The problem here is that if bar
actually exists, then it will be interpreted as the value of bar
, so we have:
fun2(foo = "bar")
#> [1] "bar"
fun2(foo = bar)
#> [1] "bar"
bar <- 1
fun2(foo = bar)
#> [1] "1"
Which is presumably not what you intended.
However, if you were going to do it this way, it probably no longer makes sense to call fun
at all. Perhaps the easiest thing to do is
fun2 <- function(foo) {
as.character(match.call()$foo)
}
fun2("bar")
#> [1] "bar"
fun2(bar)
#> [1] "bar"
bar <- 1
fun2(bar)
#> [1] "bar"