I have an expression expr
that I want to evaluate; the symbol/value pairs I need to evaluate it may be in one (or more!) of three environments, and I'm not sure which. I'd like to find a convenient, efficient way to "chain" the environments. Is there a way to do this safely while avoiding the copying of contents of environments?
Here's the setup:
env1 <- list2env(list(a=1))
env2 <- list2env(list(b=1))
env3 <- list2env(list(c=1))
expr <- quote(a+b)
So, I will need to evaluate expr
in the combination of environments env1
and env2
(but I don't necessarily know that). Any of eval(expr, env1)
; eval(expr, env2)
; and eval(expr,env3)
will fail, because none of those environments contains all of the required symbols.
Let's suppose I'm willing to assume that the symbols are either in env1
+env2
or in env1
+env3
. I could:
- Create combined environments for each of those pairs as described in this question.
problems:
- if I use one of the solutions that involves creating new environments, and one of my environments has a lot of stuff in it, this could be expensive.
- using
parent.env()<-
could be a bad idea — as described in?parent.env
:
The replacement function parent.env<- is extremely dangerous as it can be used to destructively change environments in ways that violate assumptions made by the internal C code. It may be removed in the near future.
(although, according the source history, that warning about removal "in the near future" is at least 19 years old ...)
(in fact I've already managed to induce some infinite loops playing with this approach)
- use
tryCatch(eval(call, envir=as.list(expr1), enclos=expr2),
error=function(e) {
tryCatch(eval(call, as.list(expr1), enclos=expr3))
to create an "environment within an environment"; try out the combined pairs one at a time to see which one works. Note that enclos=
only works when envir
is a list or pairlist, which is why I have to use as.list()
.
problem: I think I still end up copying the contents of expr1
into a new environment.
I could use an even more deeply nested set of tryCatch()
clauses to try out the environments one at a time before I resort to copying them, which would help avoid copying where unnecessary (but seems clunky).