I'm trying to write a function that would simply wrap around deparse()
and substitute()
like so:
get_name <- function(x) {
deparse(substitute(x))
}
The point of get_name()
is to return the character object of a function argument. get_name()
is working when called in my global environment like this:
# no problem here, returns "Variable1" as expected
get_name(x = Variable1)
[1] "Variable1"
The problem is when I try and use get_name()
in another function. Like the one below:
# a new function that uses get_name()
new_function <- function(arg1) {
get_name(x = arg1)
}
# returns "arg1"
# should be returning "Variable1"
new_function(arg1 = Variable1)
[1] "arg1"
My initial thinking is that there must be a way around this using environments. However, when trying to use eval()
it isn't working because Variable1
isn't actually an object in my global environment, it's just the value in my function argument.
I've also tried other rlang
functions like the combination of as_string()
and ensym()
, and unfortunately that didn't work.
Remember that each function call creates a new frame to store its variables in. Your get_name
function has a different frame than new_function
. You want the substitution to take place in the frame of new_function
and furthermore substitute
quotes its first argument when you just call it.
Here is a function that I think does what you want:
get_name <- function(x) {
nm <- substitute(x)
pf <- parent.frame()
deparse(do.call(substitute, list(nm,pf)))
}
We first use substitute
to get the argument that you want the name of (arg1 in your example) and store it in nm
. We do not need to deparse, because we want a language object.
Then we use parent.frame
to grab the frame of the function that called this one.
Then use do.call
to construct the call to substitute
with the name we already grabbed and the parent frame, then deparse that result.
With your example new_function
:
> get_name <- function(x) {
+ nm <- substitute(x)
+ pf <- parent.frame()
+ deparse(do.call(substitute, list(nm,pf)))
+ }
> new_function <- function(arg1) {
+ get_name(x = arg1)
+ }
> new_function(arg1 = Variable1)
[1] "Variable1"
> new_function(arg1 = something_else)
[1] "something_else"
Then you can do something like this as well:
myplot <- function(x, y) {
xl <- get_name(x)
yl <- get_name(y)
plot(x, y,
xlab=paste('x:', xl),
ylab=paste('y:', yl))
}
myplot(runif(100), rnorm(100))
And the plot has the labels based on get_name
.