From tom@@@k@||ber@ @end|ng |rom gm@||@com  Mon Apr  1 12:02:32 2019
From: tom@@@k@||ber@ @end|ng |rom gm@||@com (Tomas Kalibera)
Date: Mon, 1 Apr 2019 12:02:32 +0200
Subject: [Rd] topenv of emptyenv
In-Reply-To: <CAM2gKPaSjQp3Eq4Gy+B7RO-LgwgUoo8RV3JrA452f2v2FZAgLg@mail.gmail.com>
References: <CAM2gKPaSjQp3Eq4Gy+B7RO-LgwgUoo8RV3JrA452f2v2FZAgLg@mail.gmail.com>
Message-ID: <3b0589f3-c695-7fc4-ba74-389a4ffeead0@gmail.com>

On 3/23/19 3:26 PM, Konrad Rudolph wrote:
> I was surprised just now to find out that `topenv(emptyenv())` equals
> ? `.GlobalEnv`, not `emptyenv()`. From my understanding of the
> description of `topenv`, it should walk up the chain of enclosing
> environments (as if by calling `e = parent.env(e)` repeatedly; in
> fact, that is almost exactly its implementation in envir.c) until it
> hits a top level. However, `emptyenv()` has no enclosing environments
> so it should be its own top-level environment (I thought).
> Unfortunately the documentation on environments is relatively sparse,
> and the R Internals document doesn?t mention top-level environments.

The intuition here is that topenv() should be used with a reasonable 
execution environment and should return a reasonable execution 
environment (e.g. things you get from parent.frame(), etc). globalenv() 
is a reasonable default execution environment, emtyenv() is not). If you 
are using topenv() and especially if you are using it for something that 
is not an execution environment, there is a risk you are not doing the 
right thing - and this list may be a good place to ask for other 
solutions. topenv() as Martin said is not useful in normal user code. It 
is used in object systems (S3 and S4), in the byte-code compiler, 
sometimes in unit testing frameworks, etc.

As Martin already explained, reading the documentation as that 
"topenv(emptyenv())" would be documented to return "emptyenv()" is 
logically incorrect.

I agree, however, that it is not completely clear from the documentation 
what topenv() would do when given emptyenv() as either argument and we 
are working on addressing it. I've been looking into how much of the 
CRAN+BIOC tests (all packages) run into the special cases of topenv(), 
which btw required many hours of CPU time and some for analysis. The 
cases when topenv() is used with emptyenv() are very rare, but they 
exist (emptyenv() used as execution environment and S3 dispatch happens, 
dummy environment for S4 methods, etc).

Best
Tomas

>
> Concretely, I encountered this in the following code, which signals an
> error if `env` is the empty environment:
>
> while (! some_complex_condition(env) && ! identical(env, toplevel(env))) {
>      env = parent.env(env)
> }
>
> Of course there?s a trivial workaround (add an identity check for
> `emptyenv()` in the while loop condition) but it got me wondering if
> there?s a rationale for this result or if it?s ?accidental?/arbitrary:
> the C `topenv` implementation defaults to returning R_GlobalEnv for an
> empty environment. Is this effect actually useful (and used anywhere)?
>
> This is in R 3.4.4 but I can?t find an indication that this behaviour
> was ever changed.
>
> Cheers
>



[Rd] topenv of emptyenv
Tomas Kalibera