capture.output(eval(..., envir)) not evaluate in the expected(?) environment

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

capture.output(eval(..., envir)) not evaluate in the expected(?) environment

Henrik Bengtsson-3
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

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: capture.output(eval(..., envir)) not evaluate in the expected(?) environment

Simon Urbanek
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
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: capture.output(eval(..., envir)) not evaluate in the expected(?) environment

Henrik Bengtsson-3
Thanks for the quick answer.  I didn't know about force() function.

Cheers,

Henrik

On Wed, Nov 23, 2011 at 6:56 PM, Simon Urbanek
<[hidden email]> wrote:

> 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
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: capture.output(eval(..., envir)) not evaluate in the expected(?) environment

Simon Urbanek

On Nov 23, 2011, at 11:06 PM, Henrik Bengtsson wrote:

> Thanks for the quick answer.  I didn't know about force() function.
>

It doesn't matter how you force the argument, anything - e.g. if(is.environment(envir)) capture.output(...) would do - I used force() just to make the point that it is what is causing it.

A more simple example illustrating what happens here:

> f = function(e=parent.frame()) local(print(e))
> f()
<environment: 0x102f1f470>

> f = function(e=parent.frame()) { force(e); local(print(e)) }
> f()
<environment: R_GlobalEnv>

> f = function(e=parent.frame()) if (is.environment(e)) local(print(e))
> f()
<environment: R_GlobalEnv>

Cheers,
Simon


> Cheers,
>
> Henrik
>
> On Wed, Nov 23, 2011 at 6:56 PM, Simon Urbanek
> <[hidden email]> wrote:
>> 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
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>>>
>>
>>
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel