Here is an example from Hadley\'s advanced R book:
sample_df <- data.frame(a = 1:5, b = 5:1, c = c(5, 3, 1, 4, 1))
subset2 <- function(x, condition) {
c
This was a tricky one, so thanks for the question. The error has to do with how substitute acts when it's called on an argument. If we look at the help text from substitute():
Substitution takes place by examining each component of the parse tree as follows: If it is not a bound symbol in env, it is unchanged. If it is a promise object, i.e., a formal argument to a function or explicitly created using delayedAssign(), the expression slot of the promise replaces the symbol.
What this means is that when you evaluate condition
within the nested subset2 function, substitute
sets condition_call
to be the promise object of the unevaluated 'condition' argument. Since promise objects are pretty obscure, the definition is here: http://cran.r-project.org/doc/manuals/r-release/R-lang.html#Promise-objects
The key points from there are:
Promise objects are part of R’s lazy evaluation mechanism. They contain three slots: a value, an expression, and an environment.
and
When the argument is accessed, the stored expression is evaluated in the stored environment, and the result is returned
Basically, within the nested function, condition_call
is set to the promise object condition
, rather than the substitution of the actual expression contained within condition
. Because promise objects 'remember' the environment they come from, it seems this overrides the behavior of eval()
- so regardless of the second argument to eval(), condition_call
is evaluated within the parent environment that the argument was passed from, in which there is no 'a'.
You can create promise objects with delayedAssign()
and observe this directly:
delayedAssign("condition", a >= 4)
substitute(condition)
eval(substitute(condition), sample_df)
You can see that substitute(condition)
does not return a >= 4
, but simply condition
, and that trying to evaluate it within the environment of sample_df
fails as it does in Hadley's example.
Hopefully this is helpful, and I'm sure someone else can clarify further.