rlang (version 0.1.6)

eval_bare: Evaluate an expression in an environment

Description

eval_bare() is a lightweight version of the base function base::eval(). It does not accept supplementary data, but it is more efficient and does not clutter the evaluation stack. Technically, eval_bare() is a simple wrapper around the C function Rf_eval().

Usage

eval_bare(expr, env = parent.frame())

Arguments

expr

An expression to evaluate.

env

The environment in which to evaluate the expression.

Details

base::eval() inserts two call frames in the stack, the second of which features the envir parameter as frame environment. This may unnecessarily clutter the evaluation stack and it can change evaluation semantics with stack sensitive functions in the case where env is an evaluation environment of a stack frame (see ctxt_stack()). Since the base function eval() creates a new evaluation context with env as frame environment there are actually two contexts with the same evaluation environment on the stack when expr is evaluated. Thus, any command that looks up frames on the stack (stack sensitive functions) may find the parasite frame set up by eval() rather than the original frame targetted by env. As a result, code evaluated with base::eval() does not have the property of stack consistency, and stack sensitive functions like base::return(), base::parent.frame() may return misleading results.

See Also

with_env

Examples

Run this code
# NOT RUN {
# eval_bare() works just like base::eval():
env <- child_env(NULL, foo = "bar")
expr <- quote(foo)
eval_bare(expr, env)

# To explore the consequences of stack inconsistent semantics, let's
# create a function that evaluates `parent.frame()` deep in the call
# stack, in an environment corresponding to a frame in the middle of
# the stack. For consistency we R's lazy evaluation semantics, we'd
# expect to get the caller of that frame as result:
fn <- function(eval_fn) {
  list(
    returned_env = middle(eval_fn),
    actual_env = get_env()
  )
}
middle <- function(eval_fn) {
  deep(eval_fn, get_env())
}
deep <- function(eval_fn, eval_env) {
  expr <- quote(parent.frame())
  eval_fn(expr, eval_env)
}

# With eval_bare(), we do get the expected environment:
fn(rlang::eval_bare)

# But that's not the case with base::eval():
fn(base::eval)

# Another difference of eval_bare() compared to base::eval() is
# that it does not insert parasite frames in the evaluation stack:
get_stack <- quote(identity(ctxt_stack()))
eval_bare(get_stack)
eval(get_stack)
# }

Run the code above in your browser using DataCamp Workspace