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.

• quo() quotes its input (i.e. captures R code without evaluation), captures the current environment, and bundles them in a quosure.

• enquo() takes a symbol referring to a function argument, quotes the R code that was supplied to this argument, captures the environment where the function was called (and thus where the R code was typed), and bundles them in a quosure.

• quos() is a bit different to other functions as it returns a list of quosures. You can supply several expressions directly, e.g. quos(foo, bar), but more importantly you can also supply dots: quos(...). In the latter case, expressions forwarded through dots are captured and transformed to quosures. The environments bundled in those quosures are the ones where the code was supplied as arguments, even if the dots were forwarded multiple times across several function calls.

• new_quosure() is the only constructor that takes its arguments by value. It lets you create a quosure from an expression and an environment.

quo(expr)

new_quosure(expr, env = caller_env())

enquo(arg)

## Arguments

expr An expression. An environment specifying the lexical enclosure of the quosure. 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:

• They allow consistent scoping of quoted expressions by recording an expression along with its local environment.

• quo(), quos() and enquo() all support quasiquotation. By unquoting other quosures, you can safely combine expressions even when they come from different contexts. You can also unquote values and raw expressions depending on your needs.

• Unlike formulas, quosures self-evaluate (see eval_tidy()) within their own environment, which is why you can unquote a quosure inside another quosure and evaluate it like you've unquoted a raw expression.

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))#> mean(1:10 * 2)quo(mean(1:10 * 2))#> <quosure: local>
#> ~mean(1:10 * 2)
# It supports quasiquotation and allows unquoting (evaluating
# immediately) part of the quoted expression:
quo(mean(!! 1:10 * 2))#> <quosure: local>
#> ~mean(c(2, 4, 6, 8, 10, 12, 14, 16, 18, 20))
# 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#> <quosure: local>
#> ~var
# Here quo quotes var. Let's check that it also captures the
# environment where that symbol is defined:
identical(get_env(quo), get_env())#> [1] TRUEenv_has(quo, "var")#> [1] TRUE

# 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#> <quosure: local>
#> ~foobar * 2
# 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)#> [1] 20

# Like other formulas, quosures are normally self-quoting under
# evaluation:
eval(~var)#> ~var
#> <environment: 0x7f979ac90608>eval(quo(var))#> <quosure: local>
#> ~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)#> ~var
#> <environment: 0x7f979ac90608>eval_tidy(quo(var))#> [1] "foo"
# 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#> <quosure: local>
#> ~toupper(~letters)eval_tidy(quo)#>  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
#> [20] "T" "U" "V" "W" "X" "Y" "Z"

# 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)))#> <quosure: local>
#> ~nse_function(~foo(bar))quo(nse_function(UQE(var)))#> <quosure: local>
#> ~nse_function(foo(bar))
# This is equivalent to unquoting and taking the RHS:
quo(nse_function(!! get_expr(var)))#> <quosure: local>
#> ~nse_function(foo(bar))
# 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))#> <quosure: local> #> ~mtcars$cyl
# !!() 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))#> <quosure: local>
#> ~mtcars\$cyl

# 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))#> <quosure: local>
#> ~foo
# Literals are enquosed with the empty environment because they can
# be evaluated anywhere. The brackets indicate "empty":
quo(10L)#> <quosure: empty>
#> ~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#> <quosure: local>
#> ~foo#> <quosure: local>
#> ~foostr(quo1); str(quo2)#> <quosure: local 0x7f979e79f2e0>
#> ~foo#> <quosure: local 0x7f97a196ca78>
#> ~foo
# You can also see this address by printing the environment at the
# console:
get_env(quo1)#> <environment: 0x7f979e79f2e0>get_env(quo2)#> <environment: 0x7f97a196ca78>

# new_quosure() takes by value an expression that is already quoted:
expr <- quote(mtcars)
env <- as_env("datasets")
quo <- new_quosure(expr, env)
quo#> <quosure: local>
#> ~mtcarseval_tidy(quo)#>                      mpg cyl  disp  hp drat   wt qsec vs am gear carb
#> Mazda RX4           21.0   6 160.0 110 3.90 2.62 16.5  0  1    4    4
#> Mazda RX4 Wag       21.0   6 160.0 110 3.90 2.88 17.0  0  1    4    4
#> Datsun 710          22.8   4 108.0  93 3.85 2.32 18.6  1  1    4    1
#> Hornet 4 Drive      21.4   6 258.0 110 3.08 3.21 19.4  1  0    3    1
#> Hornet Sportabout   18.7   8 360.0 175 3.15 3.44 17.0  0  0    3    2
#> Valiant             18.1   6 225.0 105 2.76 3.46 20.2  1  0    3    1
#> Duster 360          14.3   8 360.0 245 3.21 3.57 15.8  0  0    3    4
#> Merc 240D           24.4   4 146.7  62 3.69 3.19 20.0  1  0    4    2
#> Merc 230            22.8   4 140.8  95 3.92 3.15 22.9  1  0    4    2
#> Merc 280            19.2   6 167.6 123 3.92 3.44 18.3  1  0    4    4
#> Merc 280C           17.8   6 167.6 123 3.92 3.44 18.9  1  0    4    4
#> Merc 450SE          16.4   8 275.8 180 3.07 4.07 17.4  0  0    3    3
#> Merc 450SL          17.3   8 275.8 180 3.07 3.73 17.6  0  0    3    3
#> Merc 450SLC         15.2   8 275.8 180 3.07 3.78 18.0  0  0    3    3
#> Cadillac Fleetwood  10.4   8 472.0 205 2.93 5.25 18.0  0  0    3    4
#> Lincoln Continental 10.4   8 460.0 215 3.00 5.42 17.8  0  0    3    4
#> Chrysler Imperial   14.7   8 440.0 230 3.23 5.34 17.4  0  0    3    4
#> Fiat 128            32.4   4  78.7  66 4.08 2.20 19.5  1  1    4    1
#> Honda Civic         30.4   4  75.7  52 4.93 1.61 18.5  1  1    4    2
#> Toyota Corolla      33.9   4  71.1  65 4.22 1.83 19.9  1  1    4    1
#> Toyota Corona       21.5   4 120.1  97 3.70 2.46 20.0  1  0    3    1
#> Dodge Challenger    15.5   8 318.0 150 2.76 3.52 16.9  0  0    3    2
#> AMC Javelin         15.2   8 304.0 150 3.15 3.44 17.3  0  0    3    2
#> Camaro Z28          13.3   8 350.0 245 3.73 3.84 15.4  0  0    3    4
#> Pontiac Firebird    19.2   8 400.0 175 3.08 3.85 17.1  0  0    3    2
#> Fiat X1-9           27.3   4  79.0  66 4.08 1.94 18.9  1  1    4    1
#> Porsche 914-2       26.0   4 120.3  91 4.43 2.14 16.7  0  1    5    2
#> Lotus Europa        30.4   4  95.1 113 3.77 1.51 16.9  1  1    5    2
#> Ford Pantera L      15.8   8 351.0 264 4.22 3.17 14.5  0  1    5    4
#> Ferrari Dino        19.7   6 145.0 175 3.62 2.77 15.5  0  1    5    6
#> Maserati Bora       15.0   8 301.0 335 3.54 3.57 14.6  0  1    5    8
#> Volvo 142E          21.4   4 121.0 109 4.11 2.78 18.6  1  1    4    2