Henrik Bengtsson
2011-Nov-24 02:36 UTC
[Rd] capture.output(eval(..., envir)) not evaluate in the expected(?) environment
I've noticed the following oddity where capture.output() prevents
eval() from evaluating an expression in the specified environment.
I'm not sure if it is an undocumented feature or a bug. It caused me
many hours of troubleshooting. By posting it here, it might save
someone else from doing the same exercise.
Start by defining foo() which evaluates an expression locally in a
given environment and catches the output via capture.output():
foo <- function(..., envir=parent.frame()) {
capture.output({
eval(substitute({x <- 1}), envir=envir)
})
} # foo()
Then call:
> suppressWarnings(rm(x)); foo(envir=globalenv()); print(x);
character(0)
[1] 1
This works as expected. However, if argument 'envir' is not specified
explicitly, you get:
> suppressWarnings(rm(x)); foo(); str(x);
character(0)
Error in str(x) : object 'x' not found
which shows that the internal expression of foo() is *not* evaluated
in the parent.frame(), i.e. the caller of foo(), which here should be
globalenv(). It appears that capture.output() prevents this, because
by dropping the latter:
foo <- function(..., envir=parent.frame()) {
eval(substitute({x <- 1}), envir=envir)
} # foo()
it works:
> suppressWarnings(rm(x)); foo(); str(x);
[1] 1
The workaround when still using capture.output() is to force an
explicit evaluation of argument 'envir' inside of foo() before:
foo <- function(..., envir=parent.frame()) {
stopifnot(is.environment(envir)) # Workaround
capture.output({
eval(substitute({x <- 1}), envir=envir)
})
} # foo()
which gives:> suppressWarnings(rm(x)); foo(); str(x);
character(0)
num 1
This occurs with R v2.14.0 patched and R devel:
> sessionInfo()
R version 2.14.0 Patched (2011-11-20 r57720)
Platform: x86_64-pc-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
> sessionInfo()
R Under development (unstable) (2011-11-20 r57720)
Platform: x86_64-pc-mingw32/x64 (64-bit)
locale:
[1] LC_COLLATE=English_United States.1252
[2] LC_CTYPE=English_United States.1252
[3] LC_MONETARY=English_United States.1252
[4] LC_NUMERIC=C
[5] LC_TIME=English_United States.1252
attached base packages:
[1] stats graphics grDevices utils datasets methods base
/Henrik
Simon Urbanek
2011-Nov-24 02:56 UTC
[Rd] capture.output(eval(..., envir)) not evaluate in the expected(?) environment
IMHO this has nothing to do with capture.output() per se - it's simply lazy evaluation that gets you. Add force(envir) before capture.output and it works as you expected - the parent.frame() will be different inside capture.output than outside. Cheers, Simon On Nov 23, 2011, at 9:36 PM, Henrik Bengtsson wrote:> I've noticed the following oddity where capture.output() prevents > eval() from evaluating an expression in the specified environment. > I'm not sure if it is an undocumented feature or a bug. It caused me > many hours of troubleshooting. By posting it here, it might save > someone else from doing the same exercise. > > Start by defining foo() which evaluates an expression locally in a > given environment and catches the output via capture.output(): > > foo <- function(..., envir=parent.frame()) { > capture.output({ > eval(substitute({x <- 1}), envir=envir) > }) > } # foo() > > Then call: > >> suppressWarnings(rm(x)); foo(envir=globalenv()); print(x); > character(0) > [1] 1 > > This works as expected. However, if argument 'envir' is not specified > explicitly, you get: > >> suppressWarnings(rm(x)); foo(); str(x); > character(0) > Error in str(x) : object 'x' not found > > which shows that the internal expression of foo() is *not* evaluated > in the parent.frame(), i.e. the caller of foo(), which here should be > globalenv(). It appears that capture.output() prevents this, because > by dropping the latter: > > foo <- function(..., envir=parent.frame()) { > eval(substitute({x <- 1}), envir=envir) > } # foo() > > it works: > >> suppressWarnings(rm(x)); foo(); str(x); > [1] 1 > > The workaround when still using capture.output() is to force an > explicit evaluation of argument 'envir' inside of foo() before: > > foo <- function(..., envir=parent.frame()) { > stopifnot(is.environment(envir)) # Workaround > capture.output({ > eval(substitute({x <- 1}), envir=envir) > }) > } # foo() > > which gives: >> suppressWarnings(rm(x)); foo(); str(x); > character(0) > num 1 > > This occurs with R v2.14.0 patched and R devel: > >> sessionInfo() > R version 2.14.0 Patched (2011-11-20 r57720) > Platform: x86_64-pc-mingw32/x64 (64-bit) > > locale: > [1] LC_COLLATE=English_United States.1252 > [2] LC_CTYPE=English_United States.1252 > [3] LC_MONETARY=English_United States.1252 > [4] LC_NUMERIC=C > [5] LC_TIME=English_United States.1252 > > attached base packages: > [1] stats graphics grDevices utils datasets methods base > >> sessionInfo() > R Under development (unstable) (2011-11-20 r57720) > Platform: x86_64-pc-mingw32/x64 (64-bit) > > locale: > [1] LC_COLLATE=English_United States.1252 > [2] LC_CTYPE=English_United States.1252 > [3] LC_MONETARY=English_United States.1252 > [4] LC_NUMERIC=C > [5] LC_TIME=English_United States.1252 > > attached base packages: > [1] stats graphics grDevices utils datasets methods base > > /Henrik > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel > >
Possibly Parallel Threads
- MITOOLS: Error in eval(expr, envir, enclos) : invalid 'envir' argument
- Finding the first value without warning in a loop
- Error in eval(expr, envir, enclos) : object 'Rayos' not found???
- Error in eval(expr, envir, enclos) : numeric envir arg not of length one
- bug: sticky symbol refs? (PR#9555)