[R] Understanding eval

Duncan Murdoch murdoch at stats.uwo.ca
Sat Dec 22 22:44:46 CET 2007


On 22/12/2007 3:30 PM, Charilaos Skiadas wrote:
> After many hours of debugging code, I came to the conclusion that I  
> have a fundamental misunderstanding regarding eval, and hope that  
> someone here can explain to me, why the following code acts as it does:
> 
> foo <- function(expr) {
>    eval(substitute(expr), envir=list(a=5), enclos=parent.frame())
> }
> bar <- function(er) {
>    foo(er)
> }
> 
>  > foo(a)
> [1] 5
>  > bar(a)
> Error in eval(expr, envir, enclos) : object "a" not found
> 
> 
> Now, regarding the "bar(a)" call, this is my understanding of what  
> happens, hoping someone will correct me where I'm wrong.
> 
> 1) bar is called. Its evaluation frame contains the association "er=a".
> 2) bar calls foo. So foo is called, and its evaluation frame contains  
> the association "expr=er", with enclosing environment the local  
> environment of bar.
> 3) foo calls eval.
> 4) eval starts by evaluating "substitute(expr)" in foo's environment.  
> "substitute" then locates expr in foo's environment, and replaces it  
> with er. So the result of this process is the symbol er, which is  
> what will now be evaluated by eval.
> 5) eval then creates the environment where this evaluation will take  
> place. It does that by creating an environment containing the frame  
> "a=5", and with enclosing environment the parent frame of foo, which  
> is bar's environment.
> 6) So, as I understand it, the symbol "er" is going to now be  
> evaluated in an environment where a is set to 5 and er is set to a,  
> along with whatever is in the user's workspace.

I think this part is wrong.  A better description is:

er is going to be evaluated in an environment where a is set to 5.  The 
parent of that environment is the bar evaluation frame, where er is set 
to be a promise to evaluate a in the global environment.

> 7) So the first step now is looking up a definition for er. Nothing  
> is found in the current frame, so the evaluation proceeds to bar's  
> environment, where the association "er=a" is found, so er is replaced  
> by a.

No, at this point an attempt is made to force the promise.  Promises 
have their own associated environments, and that's where the evaluation 
takes place.  In the case of the er object, the associated environment 
is the one where bar(a) was called, i.e. the global environment.

> 8) Now, and perhaps this is where I misunderstand things, the lookup  
> for a will take place. My thinking was that the lookup would start  
> from the evaluation environment that eval created, and hence would  
> locate the a=5 value. But this is clearly not what happens.
> 
> Anyway, hope someone will correct me where I'm wrong, and explain to  
> me what I am doing wrong, and ideally how to diagnose such things.

Diagnosing things like this is hard.  Promises are very difficult things 
to look at:  as soon as you try to do anything with them they get 
evaluated, and there's no way in R code to display them without that.
You can use substitute() to extract the expression part, but there's no 
way to extract the environment part.  Maybe there should be, but it's 
tricky to get the semantics right.  If the function environment() worked 
to extract the environment of a promise, then all sorts of code would 
fail where I really wanted to evaluate the arg before extracting the 
environment.

Duncan Murdoch



More information about the R-help mailing list