Question

UPDATE: I have added a variant of Roland's implementation to the kimisc package.

Is there a convenience function for exporting objects to the global environment, which can be called from a function to make objects available globally?

I'm looking for something like

export(obj.a, obj.b)

which would behave like

assign("obj.a", obj.a, .GlobalEnv)
assign("obj.b", obj.b, .GlobalEnv)

Rationale

I am aware of <<- and assign. I need this to refactor oldish code which is simply a concatenation of scripts:

input("script1.R")
input("script2.R")
input("script3.R")

script2.R uses results from script1.R, and script3.R potentially uses results from both 1 and 2. This creates a heavily polluted namespace, and I wanted to change each script

pollute <- the(namespace)
useful <- result

to

(function() {
pollute <- the(namespace)
useful <- result
export(useful)
})()

as a first cheap countermeasure.

Was it helpful?

Solution

Simply write a wrapper:

myexport <- function(...) {
  arg.list <- list(...)
  names <- all.names(match.call())[-1]
  for (i in seq_along(names)) assign(names[i],arg.list[[i]],.GlobalEnv)
}

fun <- function(a) {
  ttt <- a+1
  ttt2 <- a+2
  myexport(ttt,ttt2)
  return(a)
}

print(ttt)
#object not found error
fun(2)
#[1] 2
print(ttt)
#[1] 3
print(ttt2)
#[1] 4

Not tested thoroughly and not sure how "safe" that is.

OTHER TIPS

You can create an environment variable and use it within your export function. For example:

env <- .GlobalEnv      ## better here to create a new one :new.env()
exportx <- function(x)
{
  x <- x+1
  env$y <- x
}

exportx(3)
y
[1] 4

For example , If you want to define a global options(emulate the classic R options) in your package ,

my.options <- new.env()
setOption1 <- function(value) my.options$Option1 <- value

EDIT after OP clarification:

You can use evalq which take 2 arguments :

envir the environment in which expr is to be evaluated enclos where R looks for objects not found in envir.

Here an example:

env.script1 <- new.env()
env.script2 <- new.env()
evalq({
  x <- 2
  p <- 3 
  z <- 5 
} ,envir = env.script1,enclos=.GlobalEnv)

evalq({
  h <- x +2
} ,envir = env.script2,enclos=myenv.script1)`

You can see that all variable are created within the environnment ( like local)

 env.script2$h
[1] 4
env.script1$p
[1] 3
> env.script1$x
[1] 2

First, given your use case, I don't see how an export function is any better than using good (?) old-fashioned <<-. You could just do

(function() {
    pollute <- the(namespace)
    useful <<- result
})()

which will give the same result as what's in your example.

Second, rather than anonymous functions, it seems better form to use local, which allows you to run involved computations without littering your workspace with various temporary objects.

local({
    pollute <- the(namespace)
    useful <<- result
})

ETA: If it's important for whatever reason to avoid modifying an existing variable called useful, put an exists check in there. The same applies to the other solutions presented.

local({
    .....
    useful <- result
    if(!exists("useful", globalenv())) useful <<- useful
})
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top