2

I'm working in R, and I want to do, for example,

printx <- function() {
  x <- 1
  printy()
  return(x)
}

printy <- function() {
  print(x)
}

because I don't want to keep passing around tons of variables (also, there is no x in the global environment). Is there a way to do this? All functions can access the global environment but what about the ones between the function's environment and the global?

Ari B. Friedman
  • 71,271
  • 35
  • 175
  • 235
jclancy
  • 49,598
  • 5
  • 30
  • 34

2 Answers2

5

Maybe

printx <- function() {
  x <- 1
  printy()
  return(x)
}

printy <- function() {
  print(get('x',envir=parent.frame()))
}

> x<-0
> printy()
[1] 0
> printx()
[1] 1
[1] 1

This would use the x to be printed by printy which was associated with the environment the function was called in.

One other possibility would be to create a new environment

e1<-new.env(parent = baseenv())

> assign('x',12,envir=e1)
> x
[1] 0
> get('x',e1)
[1] 12
shhhhimhuntingrabbits
  • 7,397
  • 2
  • 23
  • 23
  • 3
    Beat me to it. Well done. Note, however, that it's [not a great idea](http://stackoverflow.com/questions/5526322/examples-of-the-perils-of-globals-in-r-and-stata). Passing around a list of parameters would be better and not much more trouble. – Ari B. Friedman Jul 31 '12 at 00:59
  • @AriB.Friedman: passing an environment is another option, but you'd have to be careful not to inadvertently modify variables in the environment, since they're not pass-by-value. – Joshua Ulrich Jul 31 '12 at 01:25
  • That's a good option also. Together with @Michael's answer that makes three alternatives. Hurrah for the question-behind-the-question. – Ari B. Friedman Jul 31 '12 at 01:48
  • Thank you, this is exactly what I was looking for. I assume if I have a function that takes a variable of the same name, assigning it will overwrite the variable from the parent environment? – jclancy Jul 31 '12 at 01:56
  • You could also just nest the definition of `printy` in `printx`, as a function's environment inherits from its definition environment. – Charles Jul 31 '12 at 07:21
3

You could use a closure to obtain similar results without the risks associated with risks alluded to above. Without knowing exactly what you're trying to do, it's difficult to present a relevant example. But the below code might be of interest...

create.functions <- function(x){
    list(
        function() x,
        function() x+1,
        function() x^2
    )

}

x <- 0

f1 <- create.functions(5)
f1[[1]]()
[1] 5
f1[[2]]()
[1] 6
f1[[3]]()
[1] 25

f2 <- create.functions(3)
f2[[1]]()
[1] 3
f2[[2]]()
[1] 4
f2[[3]]()
[1] 9

x
[1] 0

Notice that you can create a suite of functions sharing the same parameter, x, without any conflict between the parameter x and the value of x in the global environment. If you need a new set of functions where the parameter of x is differently defined, you can just create a new set.

This could even be worked such that code relying on the suite of functions need not be edited when changing the value of your parameter:

f <- create.functions(5)
f[[1]]()/f[[3]]()
[1] 0.2

f <- create.functions(3)
f[[1]]()/f[[3]]()
[1] 0.3333333

Note that the same line of code f[[1]]()/f[[3]](), returns different results depending on how your parameter x has been defined.

Michael
  • 5,808
  • 4
  • 30
  • 39