quosure {rlang}R Documentation

Create quosures

Description

Quosures are quoted expressions that keep track of an environment (just like closurefunctions). They are implemented as a subclass of one-sided formulas. They are an essential piece of the tidy evaluation framework.

Usage

quo(expr)

new_quosure(expr, env = caller_env())

enquo(arg)

Arguments

expr

An expression.

env

An environment specifying the lexical enclosure of the quosure.

arg

A symbol referring to an argument. The expression supplied to that argument will be captured unevaluated.

Value

A formula whose right-hand side contains the quoted expression supplied as argument.

Role of quosures for tidy evaluation

Quosures play an essential role thanks to these features:

See the programming withdplyr vignette for practical examples. For developers, the tidyevaluation vignette provides an overview of this approach. The quasiquotation page goes in detail over the unquoting and splicing operators.

See Also

expr() for quoting a raw expression with quasiquotation. The quasiquotation page goes over unquoting and splicing.

Examples

# 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)

[Package rlang version 0.1.1 Index]