Evaluate an expression with quosures and pronoun support
eval_tidy()
is a variant of base::eval()
that powers the tidy
evaluation framework. Like eval()
it accepts user data as
argument. Whereas eval()
simply transforms the data to an
environment, eval_tidy()
transforms it to a data mask with
as_data_mask()
. Evaluating in a data mask enables the following
features:
Quosures. Quosures are expressions bundled with an
environment. If data
is supplied, objects in the data mask
always have precedence over the quosure environment, i.e. the
data masks the environment.
Pronouns. If data
is supplied, the .env
and .data
pronouns are installed in the data mask. .env
is a reference to
the calling environment and .data
refers to the data
argument.
These pronouns lets you be explicit about where to find
values and throw errors if you try to access non-existent values.
eval_tidy(expr, data = NULL, env = caller_env())
expr |
An expression or quosure to evaluate. |
data |
A data frame, or named list or vector. Alternatively, a
data mask created with |
env |
The environment in which to evaluate |
Data masking refers to how columns or objects inside data
have
priority over objects defined in env
(or in the quosure
environment, if applicable). If there is a column var
in data
and an object var
in env
, and expr
refers to var
, the
column has priority:
var <- "this one?" data <- data.frame(var = rep("Or that one?", 3)) within <- function(data, expr) { eval_tidy(enquo(expr), data) } within(data, toupper(var)) #> [1] "OR THAT ONE?" "OR THAT ONE?" "OR THAT ONE?"
Because the columns or objects in data
are always found first,
before objects from env
, we say that the data "masks" the
environment.
base::eval()
is sufficient for simple evaluation. Use
eval_tidy()
when you'd like to support expressions referring to
the .data
pronoun, or when you need to support quosures.
If you're evaluating an expression captured with quasiquotation
support, it is recommended to use eval_tidy()
because users will
likely unquote quosures.
Note that unwrapping a quosure with quo_get_expr()
does not
guarantee that there is no quosures inside the expression. Quosures
might be unquoted anywhere. For instance, the following does not
work reliably in the presence of nested quosures:
my_quoting_fn <- function(x) { x <- enquo(x) expr <- quo_get_expr(x) env <- quo_get_env(x) eval(expr, env) } # Works: my_quoting_fn(toupper(letters)) # Fails because of a nested quosure: my_quoting_fn(toupper(!!quo(letters)))
eval_tidy()
eval_tidy()
always evaluates in a data mask, even when data
is
NULL
. Because of this, it has different stack semantics than
base::eval()
:
Lexical side effects, such as assignment with <-
, occur in the
mask rather than env
.
Functions that require the evaluation environment to correspond
to a frame on the call stack do not work. This is why return()
called from a quosure does not work.
The mask environment creates a new branch in the tree
representation of backtraces (which you can visualise in a
browser()
session with lobstr::cst()
).
See also eval_bare()
for more information about these differences.
rlang 0.3.0
Passing an environment to data
is deprecated. Please construct an
rlang data mask with new_data_mask()
.
nse-force for the second leg of the tidy evaluation framework.
# With simple quoted expressions eval_tidy() works the same way as # eval(): apple <- "apple" kiwi <- "kiwi" expr <- quote(paste(apple, kiwi)) expr eval(expr) eval_tidy(expr) # Both accept a data mask as argument: data <- list(apple = "CARROT", kiwi = "TOMATO") eval(expr, data) eval_tidy(expr, data) # In addition eval_tidy() has support for quosures: with_data <- function(data, expr) { quo <- enquo(expr) eval_tidy(quo, data) } with_data(NULL, apple) with_data(data, apple) with_data(data, list(apple, kiwi)) # Secondly eval_tidy() installs handy pronouns that allow users to # be explicit about where to find symbols: with_data(data, .data$apple) with_data(data, .env$apple) # Note that instead of using `.env` it is often equivalent and may # be preferred to unquote a value. There are two differences. First # unquoting happens earlier, when the quosure is created. Secondly, # subsetting `.env` with the `$` operator may be brittle because # `$` does not look through the parents of the environment. # # For instance using `.env$name` in a magrittr pipeline is an # instance where this poses problem, because the magrittr pipe # currently (as of v1.5.0) evaluates its operands in a *child* of # the current environment (this child environment is where it # defines the pronoun `.`). ## Not run: data %>% with_data(!!kiwi) # "kiwi" data %>% with_data(.env$kiwi) # NULL ## End(Not run)
Please choose more modern alternatives, such as Google Chrome or Mozilla Firefox.