If you don't insist on putting the variable in the global environment, variations of the following give a cleaner solution:
TraceSetup_1 <- local({ ifn = 0 igr = 0 ftrace = FALSE fn = NA gr = NA function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ ifn <<- ifn igr <<- igr ftrace <<- ftrace fn <<- fn gr <<- gr parent.env(environment()) } }) For example, TraceSetup_1 <- local({ + ifn = 0 + igr = 0 + ftrace = FALSE + fn = NA + gr = NA + function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ + ifn <<- ifn + igr <<- igr + ftrace <<- ftrace + fn <<- fn + gr <<- gr + parent.env(environment()) + } + }) > > e <- TraceSetup_1(fn = function(x) x^2) > ls(e) [1] "fn" "ftrace" "gr" "ifn" "igr" > e$fn function(x) x^2 ## let's change 'fn': > e$fn <- function(x) x^4 > e$fn function(x) x^4 Note that the environment is always the same, so can be accessed from anywhere in your code: > e2 <- environment(TraceSetup_1) > e2 <environment: 0x000000000d1af620> > identical(e2, e) [1] TRUE > If you need a new environment every time, a basic setup might be: TraceSetup_2 <- local({ staticVar1 <- NULL ## other variables here function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ ## force evaluation of the arguments ifn igr ftrace fn gr environment() } }) There is no need for local() here but usually one needs also some static variables. Now every call gives a different environment (but all have the same parent): ea <- TraceSetup_2(fn = function(x) x^2 - 2*x + 1) > ls(ea) [1] "fn" "ftrace" "gr" "ifn" "igr" > ea$fn function(x) x^2 - 2*x + 1 > > eb <- TraceSetup_2(fn = function(x) x^2 + 1) > eb$fn function(x) x^2 + 1 > > ## ea$fn is still the same: > ea$fn function(x) x^2 - 2*x + 1 > Obviously, in this case some further arrangements are needed for the environments to be made available to the external world. Hope this helps, Georgi Boshnakov -----Original Message----- From: R-package-devel [mailto:r-package-devel-boun...@r-project.org] On Behalf Of J C Nash Sent: 28 August 2018 14:18 To: Fox, John; Richard M. Heiberger Cc: List r-package-devel Subject: Re: [R-pkg-devel] Trying to work around missing functionality Indeed, it appears that globalVariables must be outside the function. However, I had quite a bit of fiddle to get things to work without errors or warnings or notes. While I now have a package that does not complain with R CMD check, I am far from satisfied that I can give a prescription. I had to remove lines in the rootfinder like envroot$fn <- fn that were used to set the function to be used inside my instrumented function, and instead call TraceSetup(fn=fn, ...) where a similar statement was given. Why that worked while the direct assignment (note, not a <<- one) did not, I do not understand. However, I will work with this for a while and try to get a better handle on it. Thanks for the pointer. As an old-time programmer from days when you even set the add table, I'm still uncomfortable just putting code in a directory and assuming it will be executed, i.e., the globals.R file. However, I now have this set to establish the global structure as follows > ## Put in R directory. > if(getRversion() >= "2.15.1") { utils::globalVariables(c('envroot')) } # Try > declaring here > groot<-list(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA, label="none") > envroot <- list2env(groot) # Note globals in FnTrace Then TraceSetup() is > TraceSetup <- function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ > envroot$ifn <- ifn > envroot$igr <- igr > envroot$ftrace <- ftrace > envroot$fn <- fn > envroot$gr <- gr > return() > } and it is called at the start of the rootfinder routine. Thus I am establishing a global, then (re-)setting values in TraceSetup(), then incrementing counters etc. in the instrumented FnTrace() that is the function for which I find the root, which calls fn() given by the "user". Messy, but I can now track progress and measure effort. I'm sure there are cleaner solutions. I suggest offline discussion would be better until such options are clearer. Thanks again. JN On 2018-08-28 12:01 AM, Fox, John wrote: > Hi John, > > It's possible that I didn’t follow what you did, but it appears as if you > call globalVariables() *inside* the function. Instead try to do as Richard > Heiberger suggested and place the call outside of the function, e.g., in a > source file in the package R directory named globals.R. (Of course, the name > of the source file containing the command isn’t important.) > > I hope this helps, > John > > ----------------------------------------------------------------- > John Fox > Professor Emeritus > McMaster University > Hamilton, Ontario, Canada > Web: https://socialsciences.mcmaster.ca/jfox/ > > > >> -----Original Message----- >> From: R-package-devel [mailto:r-package-devel-boun...@r-project.org] On >> Behalf Of J C Nash >> Sent: Monday, August 27, 2018 8:44 PM >> To: Richard M. Heiberger <r...@temple.edu> >> Cc: List r-package-devel <r-package-devel@r-project.org> >> Subject: Re: [R-pkg-devel] Trying to work around missing functionality >> >> Unfortunately, makes things much worse. I'd tried something like this >> already. >> >>> * checking examples ... ERROR >>> Running examples in ‘rootoned-Ex.R’ failed The error most likely >>> occurred in: >>> >>>> ### Name: rootwrap >>>> ### Title: zeroin: Find a single root of a function of one variable within >>>> ### a specified interval. >>>> ### Aliases: rootwrap >>>> ### Keywords: root-finding >>>> >>>> ### ** Examples >>>> >>>> # Dekker example >>>> # require(rootoned) >>>> dek <- function(x){ 1/(x-3) - 6 } >>>> r1 <- rootwrap(dek, ri=c(3.0000001, 6), ftrace=TRUE, >>>> method="uniroot") >>> Error in registerNames(names, package, ".__global__", add) : >>> The namespace for package "rootoned" is locked; no changes in the global >> variables list may be made. >>> Calls: rootwrap -> TraceSetup -> <Anonymous> -> registerNames >>> Execution halted >> >> Also had to use utils::globalVariables( ... >> >> JN >> >> >> On 2018-08-27 08:40 PM, Richard M. Heiberger wrote: >>> Does this solve the problem? >>> >>> if (getRversion() >= '2.15.1') >>> globalVariables(c('envroot')) >>> >>> I keep this in file R/globals.R >>> >>> I learned of this from John Fox's use in Rcmdr. >>> >>> On Mon, Aug 27, 2018 at 8:28 PM, J C Nash <profjcn...@gmail.com> >> wrote: >>>> In order to track progress of a variety of rootfinding or >>>> optimization routines that don't report some information I want, I'm >>>> using the following setup (this one for rootfinding). >>>> >>>> TraceSetup <- function(ifn=0, igr=0, ftrace=FALSE, fn=NA, gr=NA){ # >>>> JN: Define globals here >>>> groot<-list(ifn=ifn, igr=igr, ftrace=ftrace, fn=fn, gr=gr, label="none") >>>> envroot <<- list2env(groot) # Note globals in FnTrace >>>> ## This generates a NOTE that >>>> ## TraceSetup: no visible binding for '<<-' assignment to ‘envroot’ >>>> ## envroot<-list2env(groot, parent=.GlobalEnv) # Note globals in FnTrace >>>> - >> - this does NOT work >>>> ## utils::globalVariables("envroot") # Try declaring here -- >>>> causes errors # end globals >>>> envroot >>>> } >>>> >>>> FnTrace <- function(x,...) { >>>> # Substitute function to call when rootfinding >>>> # Evaluate fn(x, ...) >>>> val <- envroot$fn(x, ...) >>>> envroot$ifn <- envroot$ifn + 1 # probably more efficient ways >>>> if (envroot$ftrace) { >>>> cat("f(",x,")=",val," after ",envroot$ifn," ",envroot$label,"\n") >>>> } >>>> val >>>> } >>>> >>>> >>>> Perhaps there are better ways to do this, but this does seem to work quite >> well. >>>> It lets me call a rootfinder with FnTrace and get information on >>>> evaluations >> of fn(). >>>> (There's another gr() routine, suppressed here.) >>>> >>>> However, R CMD check gives a NOTE for >>>> >>>> TraceSetup: no visible binding for global variable ‘envroot’ >>>> Undefined global functions or variables: >>>> envroot >>>> >>>> The commented lines in TraceSetup suggest some of the things I've >>>> tried. Clearly I don't fully comprehend how R is grinding up the >>>> code, but searches on the net seem to indicate I am far from alone. Does >> anyone have any suggestion of a clean way to avoid the NOTE? >>>> >>>> JN >>>> >>>> ______________________________________________ >>>> R-package-devel@r-project.org mailing list >>>> https://stat.ethz.ch/mailman/listinfo/r-package-devel >> >> ______________________________________________ >> R-package-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-package-devel ______________________________________________ R-package-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel ______________________________________________ R-package-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel