R: Evaluate an expression with quosures and pronoun support

eval_tidy {rlang} | R Documentation

## Evaluate an expression with quosures and pronoun support

### Description

`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.

### Usage

    eval_tidy(expr, data = NULL, env = caller_env())

### Arguments

`expr` | An expression or quosure to evaluate.
`data` | A data frame, or named list or vector. Alternatively, a data mask created with `as_data_mask()` or `new_data_mask()`. Objects in `data` have priority over those in `env`. See the section about data masking.
`env` | The environment in which to evaluate `expr`. This environment is not applicable for quosures because they have their own environments.

### Data masking

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.

### When should eval_tidy() be used instead of eval()?

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

### Life cycle

rlang 0.3.0

Passing an environment to `data` is deprecated. Please construct an rlang data mask with `new_data_mask()`.

### See Also

nse-force for the second leg of the tidy evaluation framework.

### Examples

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

[Package rlang version 0.4.3 Index]