Defuse R expressions
The defusing operators expr()
and enquo()
prevent the
evaluation of R code. Defusing is also known as quoting, and is
done in base R by quote()
and substitute()
. When a function
argument is defused, R doesn't return its value like it normally
would but it returns the R expression describing how to make the
value. These defused expressions are like blueprints for computing
values.
There are two main ways to defuse expressions, to which correspond
the two functions expr()
and enquo()
. Whereas expr()
defuses
your own expression, enquo()
defuses expressions supplied as
argument by the user of a function. See section on function
arguments for more on this distinction.
The main purpose of defusing evaluation of an expression is to
enable data-masking, where an expression is evaluated in the
context of a data frame so that you can write var
instead of
data$var
. The expression is defused so it can be resumed later
on, in a context where the data-variables have been defined.
Defusing prevents the evaluation of R code, but you can still force
evaluation inside a defused expression with the forcing operators !!
and !!!
.
expr(expr) enexpr(arg) exprs( ..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"), .unquote_names = TRUE ) enexprs( ..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last", "error"), .check_assign = FALSE ) ensym(arg) ensyms( ..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last", "error"), .check_assign = FALSE ) quo(expr) enquo(arg) quos( ..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"), .unquote_names = TRUE ) enquos( ..., .named = FALSE, .ignore_empty = c("trailing", "none", "all"), .unquote_names = TRUE, .homonyms = c("keep", "first", "last", "error"), .check_assign = FALSE )
expr |
An expression. |
arg |
A symbol representing an argument. The expression supplied to that argument will be captured instead of being evaluated. |
... |
For |
.named |
Whether to ensure all dots are named. Unnamed
elements are processed with |
.ignore_empty |
Whether to ignore empty arguments. Can be one
of |
.unquote_names |
Whether to treat |
.homonyms |
How to treat arguments with the same name. The
default, |
.check_assign |
Whether to check for |
Calls, like f(1, 2, 3)
or 1 + 1
represent the action of
calling a function to compute a new value, such as a vector.
Symbols, like x
or df
, represent named objects. When the
object pointed to by the symbol was defined in a function or in
the global environment, we call it an environment-variable. When
the object is a column in a data frame, we call it a
data-variable.
You can create new call or symbol objects by using the defusing
function expr()
:
# Create a symbol representing objects called `foo` expr(foo) # Create a call representing the computation of the mean of `foo` expr(mean(foo, na.rm = TRUE))
Defusing is not the only way to create defused expressions. You can also assemble them from data:
# Assemble a symbol from a string var <- "foo" sym(var) # Assemble a call from strings, symbols, and other objects call("mean", sym(var), na.rm = TRUE)
There are two points of view when it comes to defusing an expression:
You can defuse expressions that you supply with expr()
. This
is one way of creating symbols and calls (see previous section).
You can defuse the expressions supplied by the user of your
function with the operators starting with en
like ensym()
,
enquo()
and their plural variants. They defuse function
arguments .
If you inspect the return values of expr()
and enquo()
, you'll
notice that the latter doesn't return a raw expression like the
former. Instead it returns a quosure, a wrapper containing an
expression and an environment. R needs information about the
environment to properly evaluate the argument expression because it
comes from a different context than the current function.
See the quosure help topic about tools to work with quosures.
The defusing operator expr()
is similar to quote()
. Like
bquote()
, it allows forcing evaluation of parts
of an expression.
The plural variant exprs()
is similar to alist()
.
The argument-defusing operator enquo()
is similar to
substitute()
.
# expr() and exprs() capture expressions that you supply: expr(symbol) exprs(several, such, symbols) # enexpr() and enexprs() capture expressions that your user supplied: expr_inputs <- function(arg, ...) { user_exprs <- enexprs(arg, ...) user_exprs } expr_inputs(hello) expr_inputs(hello, bonjour, ciao) # ensym() and ensyms() provide additional type checking to ensure # the user calling your function has supplied bare object names: sym_inputs <- function(...) { user_symbols <- ensyms(...) user_symbols } sym_inputs(hello, "bonjour") ## sym_inputs(say(hello)) # Error: Must supply symbols or strings expr_inputs(say(hello)) # All these quoting functions have quasiquotation support. This # means that you can unquote (evaluate and inline) part of the # captured expression: what <- sym("bonjour") expr(say(what)) expr(say(!!what)) # This also applies to expressions supplied by the user. This is # like an escape hatch that allows control over the captured # expression: expr_inputs(say(!!what), !!what) # Finally, you can capture expressions as quosures. A quosure is an # object that contains both the expression and its environment: quo <- quo(letters) quo get_expr(quo) get_env(quo) # Quosures can be evaluated with eval_tidy(): eval_tidy(quo) # They have the nice property that you can pass them around from # context to context (that is, from function to function) and they # still evaluate in their original environment: multiply_expr_by_10 <- function(expr) { # We capture the user expression and its environment: expr <- enquo(expr) # Then create an object that only exists in this function: local_ten <- 10 # Now let's create a multiplication expression that (a) inlines # the user expression as LHS (still wrapped in its quosure) and # (b) refers to the local object in the RHS: quo(!!expr * local_ten) } quo <- multiply_expr_by_10(2 + 3) # The local parts of the quosure are printed in colour if your # terminal is capable of displaying colours: quo # All the quosures in the expression evaluate in their original # context. The local objects are looked up properly and we get the # expected result: eval_tidy(quo)
Please choose more modern alternatives, such as Google Chrome or Mozilla Firefox.