Detaching and re-attaching “tools:rstudio”

2019-06-27 04:13发布

问题:

a.k.a playing with fire...

The following does not work:

rstd.obj <- as.environment("tools:rstudio")
detach("tools:rstudio")
attach(rstd.obj, name="tools:rstudio")

Well, it seems to work, but then all sorts of weird errors start popping up. The problem is that very annoyingly (though I'm sure for a very good reason) attach makes a copy of the environment and attaches that, instead of attaching the environment directly:

rstd.obj
# <environment: 0x000000000930edd0>
# attr(,"name")
# [1] "tools:rstudio"
as.environment("tools:rstudio")
# <environment: 0x000000000a21b4c8>
# attr(,"name")
# [1] "tools:rstudio"

Notice how the environments are actually different (this is also confirmed if you look at the source code for do_attach in src/main/envir.c@2124(R3.0.2) where the copy is made).

This, however, works totally fine (after restarting RStudio to reset everything):

rstd.obj <- as.environment("tools:rstudio")
rstd.parent <- as.environment("package:stats")  # this was #3 on search path for me
detach("tools:rstudio")

# WARNING: YOU'RE PLAYING WITH FIRE IF YOU RUN THIS, DO
# SO AT YOUR OWN RISK:

parent.env(.GlobalEnv) <- rstd.obj
parent.env(rstd.obj) <- rstd.parent

Instead of using detach/attach, we just detach, and forcibly insert the object back into the search path using parent.env<-. On the flipside, I'm guessing doing the above is probably close to what R Core had in mind when they warned 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.

Another alternative to get around this problem is to use detach/attach, but then cycle through all the functions in the tools:rstudio environment on the search path and reset their environments to the copy of the original environment now on the search path (incidentally, this is why Rstudio starts breaking: the function environments are still the object removed from the search path, but that environment is not in the search path anymore, only a copy of it). This feels incredibly hacky though.

Also, if anyone knows more details about what the "assumptions made by the internal C code" are I'd be very interested to hear them. Obviously, we could introduce circularities in the search path (no, I didn't accidentally just do that messing around with these examples...), but are there other problems as well?

EDIT: regarding the above, super useful tidbit from R-devel:

I'd like to propose a change to the R language so that calling 'parent.env<-' on a package namespace or package imports is a runtime error. ... I'd also like to make calling parent.env<- on an environment on the call stack an error, for the same reasons, but it's not so obvious to me how to implement that efficiently right now. Could we at least document that as being 'undefined behaviour'?

And Luke Tierney's answer:

I'll look into it

This seems to confirm the concern is changing the call stack in call or search path in a way R may not track, as opposed to generally thinking parent.env<- is dangerous for other environment chains (clearly reading b/w lines here).