Renaud Gaujoux
2009-Aug-20 08:27 UTC
[R] eval and evironments: call local function in a global function
Hi, in my project I want the user to be able to write hook functions that are in turn called in my main code. I'd like the user's hooks to be able to call some function that set a variable outside their running environment. The trick is that this variable is not global, but defined on runtime before calling the hooks, and I don't want to leave any trace (i.e. global variables) after the main code has finished. I thought that the following would work but it doesn't. I guess I got too messy with environment and enclosures: # global function defined by the user fun.global <- function(){ message('fun.global') setVar(5) # } # my main code main <- function(){ message('main') # define a function to set some local variable setVar <- local({ l.var <- 0 function(value){ message('setVar') l.var <<- value } }) .workspace <- environment(setVar) environment(setVar) <- new.env() eval(fun.global(), enclos=environment(setVar)) print(get('l.var', envir=.workspace, inherits=FALSE)) } main() I get the following output: > main > fun.global > Error in fun.global() : could not find function "setVar" There is definitely a problem of lookup somewhere. I first tried without eval, as I thought that function setVar would then be defined in a parent environment of the call to fun.global, but it does not work either. Can anybody tell me what's the problem and how I should do my stuff? Thanks, Renaud
Gabor Grothendieck
2009-Aug-20 12:01 UTC
[R] eval and evironments: call local function in a global function
I am not sure what the purpose of workspace is so I have eliminated it in the following. We just use the environment within main and when main exits all its variables go too so that seems sufficient. fun.global <- function() { message('fun.global'); setVar(5) } main <- function() { l.var <- 0 setVar <- function(value) { message("set Var"); l.var <<- value } environment(fun.global) <- environment() fun.global() print(l.var) } main() We could also recognize that there is an implicit object here with methods setVar and fun.global and property l.var so using proto: library(proto) fun.global <- function(obj) { message("setVar"); obj$setVar(5) } main <- function() { p <- proto(l.var = 0, setVar = function(obj, value) { message("setVar"); obj$l.var <- value }, fun.global = fun.global) p$fun.global() print(p$l.var) } main() On Thu, Aug 20, 2009 at 4:27 AM, Renaud Gaujoux<getoxxx at gmail.com> wrote:> Hi, > > in my project I want the user to be able to write hook functions that are in > turn called in my main code. I'd like the user's hooks to be able to call > some function that set a variable outside their running environment. The > trick is that this variable is not global, but defined on runtime before > calling the hooks, and I don't want to leave any trace (i.e. global > variables) after the main code has finished. > > I thought that the following would work but it doesn't. I guess I got too > messy with environment and enclosures: > > # global function defined by the user > fun.global <- function(){ > ? message('fun.global') > ? setVar(5) # > } > > > # my main code > main <- function(){ > ? message('main') > > ? # define a function to set some local variable > ? setVar <- local({ > ? l.var <- 0 > ? function(value){ > ? ? ? message('setVar') > ? ? ?l.var <<- value > ? } > ? }) > ? .workspace <- environment(setVar) > ? environment(setVar) <- new.env() > > ? eval(fun.global(), enclos=environment(setVar)) > ? print(get('l.var', envir=.workspace, inherits=FALSE)) > } > > main() > > I get the following output: >> main >> fun.global >> Error in fun.global() : could not find function "setVar" > > There is definitely a problem of lookup somewhere. I first tried without > eval, as I thought that function setVar would then be defined in a parent > environment of the call to fun.global, but it does not work either. > Can anybody tell me what's the problem and how I should do my stuff? > > Thanks, > Renaud > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >
Duncan Murdoch
2009-Aug-20 15:22 UTC
[R] eval and evironments: call local function in a global function
On 8/20/2009 4:27 AM, Renaud Gaujoux wrote:> Hi, > > in my project I want the user to be able to write hook functions that > are in turn called in my main code. I'd like the user's hooks to be able > to call some function that set a variable outside their running > environment.The trick is that this variable is not global, but defined> on runtime before calling the hooks, and I don't want to leave any trace > (i.e. global variables) after the main code has finished.The best way to do this is to pass the function (setVar below) as an argument to the user's function. If it's the user's function, you have no business messing with it by changing its environment. How do you know the user didn't spend hours working out some crazy scheme of creating a nested function with a carefully crafted environment, and evaluation of his function depends on you leaving it alone?> > I thought that the following would work but it doesn't. I guess I got > too messy with environment and enclosures: > > # global function defined by the user > fun.global <- function(){ > message('fun.global') > setVar(5) # > }Pass setVar as an arg: fun.global <- function(setVar) { message('fun.global') setVar(5) }> > > # my main code > main <- function(){ > message('main') > > # define a function to set some local variable > setVar <- local({ > l.var <- 0 > function(value){ > message('setVar') > l.var <<- value > } > }) > .workspace <- environment(setVar) > environment(setVar) <- new.env() > > eval(fun.global(), enclos=environment(setVar)) > print(get('l.var', envir=.workspace, inherits=FALSE)) > }I wouldn't bother with the extra layer of local(), just put l.var in main's evalution frame. (Since you're the one writing setVar, you can avoid any name clashes.) That is: main <- function() { message('main') l.var <- 0 setVar <- function(value) { message('setVar') l.var <<- value } fun.global(setVar) print(l.var) } Duncan Murdoch> > main() > > I get the following output: > > main > > fun.global > > Error in fun.global() : could not find function "setVar" > > There is definitely a problem of lookup somewhere. I first tried without > eval, as I thought that function setVar would then be defined in a > parent environment of the call to fun.global, but it does not work either. > Can anybody tell me what's the problem and how I should do my stuff? > > Thanks, > Renaud > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.