16

I am still struggling with R scoping and environments. I would like to be able to construct simple helper functions that get called from my 'main' functions that can directly reference all the variables within those main functions - but I don't want to have to define the helper functions within each of my main functions.

helpFunction<-function(){
#can I add a line here to alter the environment of this helper function to that of the calling function?
return(importantVar1+1)
}

mainFunction<-function(importantVar1){
return(helpFunction())
}

mainFunction(importantVar1=3) #so this should output 4
Charlie
  • 481
  • 4
  • 16

3 Answers3

24

If you declare each of your functions to be used with dynamic scoping at the beginning of mainfunction as shown in the example below it will work. Using helpFunction defined in the question:

mainfunction <- function(importantVar1) {

    # declare each of your functions to be used with dynamic scoping like this:
    environment(helpFunction) <- environment()

    helpFunction()
}

mainfunction(importantVar1=3)

The source of the helper functions themselves does not need to be modified.

By the way you might want to look into Reference Classes or the proto package since it seems as if you are trying to do object oriented programming through the back door.

G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
9

Well, a function cannot change it's default environment, but you can use eval to run code in a different environment. I'm not sure this exactly qualifies as elegant, but this should work:

helpFunction<-function(){
    eval(quote(importantVar1+1), parent.frame())
}

mainFunction<-function(importantVar1){
    return(helpFunction())
}

mainFunction(importantVar1=3)
theforestecologist
  • 4,667
  • 5
  • 54
  • 91
MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • Thanks. This will be helpful sometimes - Grothendieck's answer achieves very similar but I like the one line approach. – Charlie May 28 '14 at 12:47
4

The R way would be passing function arguments:

helpFunction<-function(x){ 
#you can also use importantVar1 as argument name instead of x
#it will be local to this helper function, but since you pass the value
#it will have the same value as in the main function
  x+1
}

mainFunction<-function(importantVar1){
  helpFunction(importantVar1)
}

mainFunction(importantVar1=3)
#[1] 4

Edit since you claim it "doesn't work":

helpFunction<-function(importantVar1){ 
  importantVar1+1
}

mainFunction<-function(importantVar1){
  helpFunction(importantVar1)
}

mainFunction(importantVar1=3)
#[1] 4
Roland
  • 127,288
  • 10
  • 191
  • 288
  • 1
    There's no other solution? This approach gets really tiresome when many variables need arbitrary renaming... makes helper functions less helpful. – Charlie May 27 '14 at 13:33
  • I don't see how this approach needs renaming of variables? If you hard-code a variable name into your helper function that seems not very useful. – Roland May 27 '14 at 13:43
  • I'm working on a package that does a lot of different things on a limited range of variables I guess. For instance, I have a timepoints variable that is relevant in every function, redefining it for each is cumbersome. – Charlie May 27 '14 at 14:09
  • I still don't understand why you think you need to redefine anything? I agree with @G.Grothendieck, it sounds like you want to create an object and a bunch of methods for it. Look into object oriented programming with R. – Roland May 27 '14 at 14:22
  • if my main function is called by mainfunction(Tpoints,latents,predictors), and in my helper functions I want to use the values of variables Tpoints, latents, predictors, then I am forced to rename them, just as you renamed importantVar1 to x. The first solution I tried was setting my helper to include defaults of Tpoints=Tpoints, latents=latents, predictors=predictors, but yes, that fails :) I will look into the oop side of things, but probably just work around it... – Charlie May 27 '14 at 14:42
  • No, you are not forced to rename them. I only did that for clarity. `helpFunction <- function(importantVar1) importantVar1+1` would work as well. – Roland May 27 '14 at 14:48
  • it doesn't work for me, can you edit the answer with your suggestion? – Charlie May 27 '14 at 14:59
  • thanks, I was looking at it the wrong way ;) Still not what I'd like but maybe neater than I have. – Charlie May 27 '14 at 15:21
  • 2
    You still haven't make me understand what you'd like and why that would be a good idea (except maybe typing fewer characters when writing the functions?). – Roland May 27 '14 at 15:38
  • Yes,typing fewer characters when writing such functions and outputting the results directly into the calling environment would be convenient at times. Maybe it's bad / ugly programming, maybe my package is doing unusual things, whatever, this is what I wanted :) – Charlie May 28 '14 at 12:43