# NOT RUN {
# quo() is a quotation function just like expr() and quote():
expr(mean(1:10 * 2))
quo(mean(1:10 * 2))
# It supports quasiquotation and allows unquoting (evaluating
# immediately) part of the quoted expression:
quo(mean(!! 1:10 * 2))
# What makes quo() often safer to use than quote() and expr() is
# that it keeps track of the contextual environment. This is
# especially important if you're referring to local variables in
# the expression:
var <- "foo"
quo <- quo(var)
quo
# Here `quo` quotes `var`. Let's check that it also captures the
# environment where that symbol is defined:
identical(get_env(quo), get_env())
env_has(quo, "var")
# Keeping track of the environment is important when you quote an
# expression in a context (that is, a particular function frame)
# and pass it around to other functions (which will be run in their
# own evaluation frame):
fn <- function() {
foobar <- 10
quo(foobar * 2)
}
quo <- fn()
quo
# `foobar` is not defined here but was defined in `fn()`'s
# evaluation frame. However, the quosure keeps track of that frame
# and is safe to evaluate:
eval_tidy(quo)
# Like other formulas, quosures are normally self-quoting under
# evaluation:
eval(~var)
eval(quo(var))
# But eval_tidy() evaluates expressions in a special environment
# (called the overscope) where they become promises. They
# self-evaluate under evaluation:
eval_tidy(~var)
eval_tidy(quo(var))
# Note that it's perfectly fine to unquote quosures within
# quosures, as long as you evaluate with eval_tidy():
quo <- quo(letters)
quo <- quo(toupper(!! quo))
quo
eval_tidy(quo)
# Quoting as a quosure is necessary to preserve scope information
# and make sure objects are looked up in the right place. However,
# there are situations where it can get in the way. This is the
# case when you deal with non-tidy NSE functions that do not
# understand formulas. You can inline the RHS of a formula in a
# call thanks to the UQE() operator:
nse_function <- function(arg) substitute(arg)
var <- locally(quo(foo(bar)))
quo(nse_function(UQ(var)))
quo(nse_function(UQE(var)))
# This is equivalent to unquoting and taking the RHS:
quo(nse_function(!! get_expr(var)))
# One of the most important old-style NSE function is the dollar
# operator. You need to use UQE() for subsetting with dollar:
var <- quo(cyl)
quo(mtcars$UQE(var))
# `!!`() is also treated as a shortcut. It is meant for situations
# where the bang operator would not parse, such as subsetting with
# $. Since that's its main purpose, we've made it a shortcut for
# UQE() rather than UQ():
var <- quo(cyl)
quo(mtcars$`!!`(var))
# When a quosure is printed in the console, the brackets indicate
# if the enclosure is the global environment or a local one:
locally(quo(foo))
# Literals are enquosed with the empty environment because they can
# be evaluated anywhere. The brackets indicate "empty":
quo(10L)
# To differentiate local environments, use str(). It prints the
# machine address of the environment:
quo1 <- locally(quo(foo))
quo2 <- locally(quo(foo))
quo1; quo2
str(quo1); str(quo2)
# You can also see this address by printing the environment at the
# console:
get_env(quo1)
get_env(quo2)
# new_quosure() takes by value an expression that is already quoted:
expr <- quote(mtcars)
env <- as_env("datasets")
quo <- new_quosure(expr, env)
quo
eval_tidy(quo)
# }
Run the code above in your browser using DataLab