Function factories : how to "free" a manufactured function from its enclosing environment ?

In the following example I'm building a function factory, my issue is that my manufactured function is not considering the definition of x that I want :

foo <- function(){
  x <- "x def in foo"
  function(expr){
    y <- "y def in bar"
    eval(substitute(expr))
  }
}
x <- "x def in global"
bar <- foo()
bar(c(x,y))
# [1] "x def in foo" "y def in bar"

I found 3 different ways of dealing with this, but I'm not sure which or if either of those is idiomatic or if they come with caveats.

I can set the environment of my manufactured function to .GlobalEnv :

foo <- function(){
  x <- "x def in foo"
  bar <- function(expr){
    y <- "y def in bar"
    eval(substitute(expr))
  }
  environment(bar) <- .GlobalEnv
  bar
}
x <- "x def in global"
bar <- foo()
bar(c(x,y))
# [1] "x def in global" "y def in bar"

Or I can cleanup my enclosing environment with on.exit

foo <- function(){
  x <- "x def in foo"
  on.exit(rm(list=ls()))   # or on.exit(rm(x))
  function(expr){
    y <- "y def in bar"
    eval(substitute(expr))
  }
}
x <- "x def in global"
bar <- foo()
bar(c(x,y))
# [1] "x def in global" "y def in bar"

Or I can evaluate within a restricted environment, setting enclos in the parent frame of bar :

foo <- function(){
  x <- "x def in foo"
  function(expr){
    y <- "y def in bar"
    eval(substitute(expr), 
         envir = list(y = y),
         enclos = parent.frame(2))
  }
}
x <- "x def in global"
bar <- foo()
bar(c(x,y))
# [1] "x def in global" "y def in bar"

It seems to me that the second solution might be the cleanest as I think other solutions clutter the memory with the "x def in foo" value , but maybe there are other better options or I'm overlooking something ?

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.