As it turns out, my approach was a bit aggressive. A critical package was using it and could see my new attach!
I will just warn, and encourage: .First <- function() { gcr <- new.env() gcr$unsafe.attach <- attach gcr$attach <- function(...) { warning("NEVER USE ATTACH! Use `unsafe.attach` if you must.") unsafe.attach(...) } base::attach(gcr, name="gcr", warn.conflicts = FALSE) } Grant Rettke | ACM, ASA, FSF, IEEE, SIAM g...@wisdomandwonder.com | http://www.wisdomandwonder.com/ “Wisdom begins in wonder.” --Socrates ((λ (x) (x x)) (λ (x) (x x))) “Life has become immeasurably better since I have been forced to stop taking it seriously.” --Thompson On Sun, Aug 10, 2014 at 9:13 AM, Grant Rettke <g...@wisdomandwonder.com> wrote: > Thank you for that pleasant and concise explanation! > > I will keep at it. > Grant Rettke | ACM, ASA, FSF, IEEE, SIAM > g...@wisdomandwonder.com | http://www.wisdomandwonder.com/ > “Wisdom begins in wonder.” --Socrates > ((λ (x) (x x)) (λ (x) (x x))) > “Life has become immeasurably better since I have been forced to stop > taking it seriously.” --Thompson > > > On Tue, Aug 5, 2014 at 7:54 PM, Winston Chang <winstoncha...@gmail.com> wrote: >> On Tue, Aug 5, 2014 at 4:37 PM, Grant Rettke <g...@wisdomandwonder.com> >> wrote: >>> >>> That is delightful. >>> >>> When I run it like this: >>> • Start R >>> • Nothing in .Rprofile >>> • Paste in your code >>> ╭──── >>> │ gcrenv <- new.env() >>> │ gcrenv$attach.old <- attach >>> │ gcrenv$attach <- function(...){stop("NEVER USE ATTACH")} >>> │ base::attach(gcrenv, name="gcr", warn.conflicts = FALSE) >>> ╰──── >>> • I get exactly what is expected, I think >>> ╭──── >>> │ search() >>> ╰──── >>> ╭──── >>> │ [1] ".GlobalEnv" "gcr" "ESSR" >>> │ [4] "package:stats" "package:graphics" "package:grDevices" >>> │ [7] "package:utils" "package:datasets" "package:methods" >>> │ [10] "Autoloads" "package:base" >>> ╰──── >>> >>> Just to be sure: >>> • Is that what is expected? >>> • I am surprised because I thought that `gcr' would come first before >>> `.GlobalEnv' >>> • Perhaps I mis understand, as `.GlobalEnv' is actually the "REPL"? >>> >>> My goal is to move that to my .Rprofile so that it is "always run" and I >>> can forget about it more or less. >>> >>> Reading [this] I felt like `.First' would be the right place to put it, >>> but then read further to find that packages are only loaded /after/ >>> `.First' has completed. Curious, I tried it just to be sure. I am now >>> :). >>> >>> This is the .Rprofile file: >>> >>> ╭──── >>> │ cat(".Rprofile: Setting CMU repository\n") >>> │ r = getOption("repos") >>> │ r["CRAN"] = "http://lib.stat.cmu.edu/R/CRAN/" >>> │ options(repos = r) >>> │ rm(r) >>> │ >>> │ .First <- function() { >>> │ «same code as above» >>> │ } >>> ╰──── >>> >>> (I included the repository load, and understand it should not impact >>> things here) >>> >>> This is run after normal startup of R: >>> >>> ╭──── >>> │ search() >>> ╰──── >>> ╭──── >>> │ [1] ".GlobalEnv" "package:stats" "package:graphics" >>> │ [4] "package:grDevices" "package:utils" "package:datasets" >>> │ [7] "gcr" "package:methods" "Autoloads" >>> │ [10] "package:base" >>> ╰──── >>> >>> When I read this, I read it as: >>> • My rebind of `attach' occurs >>> • Then all of the packages are loaded and they are referring to >>> my-rebound `attach' >>> • That is a problem because it *will* break package code >>> • Clearly me putting that code in `.Rprofile' is the wrong place. >>> >> >> That order for search path should actually be fine. To understand why, >> you first have to know the difference between the _binding_ >> environment for an object, and the _enclosing_ environment for a >> function. >> >> The binding environment is where you can find an object. For example, >> in the global env, you have a bunch bindings (we often call them >> variables), that point to various objects - vectors, data frames, >> other environments, etc. >> >> The enclosing environment for a function is where the function "runs >> in" when it's called. >> >> Most R objects have just a binding environment (a variable or >> reference that points to the object); functions also have an enclosing >> environment. These two environments aren't necessarily the same. >> >> When you run search(), it shows the set of environments where R will >> look for an object of a given name, when you run stuff at the console >> (and are in the global env). The trick is that, although you can find >> a function (they are bound bound) in one of these _package_ >> environments, those functions run in (are enclosed by) a different >> environment: the a corresponding _namespace_ environment. >> >> The way that a namespace environment is set up with the arrangement of >> its ancestor environments, it will find the base namespace version of >> `attach` before it finds yours, even if your personal gcr environment >> comes early in the search path. >> >> ========================= >> # Here's an example to illustrate. The `utils::alarm` function calls >> `cat`, which is in base. >> >> alarm >> # function () >> # { >> # cat("\a") >> # flush.console() >> # } >> # <environment: namespace:utils> >> >> >> # Running it makes the screen flash or beep >> alarm() >> # [screen flashes] >> >> >> # We'll put a replacement version of cat early in the search path, >> between utils and base >> my_stuff <- new.env() >> my_stuff$cat <- function(...) stop("Tried to call cat") >> base::attach(my_stuff, pos=length(search()) - 1, name="my_stuff") >> >> search() >> # [1] ".GlobalEnv" "tools:rstudio" "package:stats" >> "package:graphics" >> # [5] "package:grDevices" "package:utils" "package:datasets" >> "package:methods" >> # [9] "my_stuff" "Autoloads" "package:base" >> >> # Calling cat from the console gives the error, as expected >> cat() >> # Error in cat() : Tried to call cat >> >> # But when we run alarm(), it still gets the real version of `cat()`, >> # because it finds the the original base namespace version of cat >> # before it finds yours. >> alarm() >> # [screen flashes] >> >> ========================== >> >> You can even alter package environments without affecting the >> corresponding namespace environment. The exception to the package and >> namespace environments being distinct is the base environment; change >> one and you change the other. (I just realized this and have to >> retract my earlier statement about the behavior being different if >> change attach in the base package env vs. the base namespace env.) >> >> -Winston ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel