I recently notices that rlang::sym
doesn't seem to work in anonymous functions and I don't understand why. Here an example, it's pretty clumsy and ugly but I think it illustrates the point
require(tidyverse)
data <- tibble(x1 = letters[1:3],
x2 = letters[4:6],
val = 1:3)
get_it <- function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}
get_it("x1", "x2")
This defines some toy data and a (horrible) function that essentially renames the columns based on column names. Now I can do the same thing for different combinations of a and b:
d <- tibble(x = c("x1", "x2"),
y = c("x2", "x1"))
d %>% mutate(tmp = map2(x, y, get_it))
However, if I try to do the exact same thing with an anonymous function it doesn't work:
d %>% mutate(tmp = map2(x, y, function(a, b){
data %>%
mutate(y1 = !!rlang::sym(a)) %>%
mutate(y2 = !!rlang::sym(b)) %>%
select(y1, y2, val)
}))
This fails with object 'a' not found
even though the functions are exactly the same just here it is anonymous. Can anyone explain why?
The issue is not anonymous functions, but the operator precedence of
!!
. The help page for!!
states thatThis implies that when you write a complex NSE expression, such as
select
insidemutate
, the unquoting will take place in the environment of the expression as a whole. As pointed out by @lionel, the unquoting then takes precedence over other things, such as creation of anonymous function environments.In your case the
!!
unquoting is done with respect to the outermutate()
, which then attempts to find columnx1
insided
, notdata
. There are two possible solutions:1) Pull the expression involving
!!
into a standalone function (as you've done in your question):2) Replace
!!
witheval
to delay expression evaluation: