What is the difference between ensym and enquo when programming with dplyr?
Here is one example illustrating one difference (namely that enquo
captures the calling environment and ensym
doesn't). Hopefully it speaks for itself:
library(rlang)
f <- function(x) {
foo <- 42
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
foo <- 3
f(foo)
# [1] 42
# [1] 3
Or the slightly more convoluted:
library(rlang)
myenv <- new.env()
local(envir = myenv, {
foo <- 17
g <- function(x) {
print(eval_tidy(quo(!! ensym(x))))
print(eval_tidy(quo(!! enquo(x))))
}
})
foo <- 123
myenv$g(foo)
#> [1] 17
#> [1] 123
Created on 2019-09-18 by the reprex package (v0.3.0)
The difference is often not noticeable when using dplyr since it is foolproof enough to always look up names in the context of the .data
argument first.
Another take :
library(rlang)
library(dplyr, warn.conflicts = FALSE)
test <- function(x){
Species <- "bar"
cat("--- enquo builds a quosure from any expression\n")
print(enquo(x))
cat("--- ensym captures a symbol or a literal string as a symbol\n")
print(ensym(x))
cat("--- evaltidy will evaluate the quosure in its environment\n")
print(eval_tidy(enquo(x)))
cat("--- evaltidy will evaluate a symbol locally\n")
print(eval_tidy(ensym(x)))
cat("--- but both work fine where the environment doesn't matter\n")
identical(select(iris,!!ensym(x)), select(iris,!!enquo(x)))
}
Species = "foo"
test(Species)
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^Species
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "foo"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test("Species")
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^"Species"
#> env: empty
#> --- ensym captures a symbol or a literal string as a symbol
#> Species
#> --- evaltidy will evaluate the quosure in its environment
#> [1] "Species"
#> --- evaltidy will evaluate a symbol locally
#> [1] "bar"
#> --- but both work fine where the environment doesn't matter
#> [1] TRUE
test(paste0("Spec","ies"))
#> --- enquo builds a quosure from any expression
#> <quosure>
#> expr: ^paste0("Spec", "ies")
#> env: global
#> --- ensym captures a symbol or a literal string as a symbol
#> Only strings can be converted to symbols
Created on 2019-09-23 by the reprex package (v0.3.0)