Set a functions environment to that of the calling environment (parent.frame) from within function
Asked Answered
D

3

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
Donaugh answered 27/5, 2014 at 13:17 Comment(0)
P
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)
Praetor answered 27/5, 2014 at 13:42 Comment(1)
Thanks. This will be helpful sometimes - Grothendieck's answer achieves very similar but I like the one line approach.Donaugh
S
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.

Spiegel answered 27/5, 2014 at 13:53 Comment(0)
P
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)
Praetor answered 27/5, 2014 at 13:42 Comment(1)
Thanks. This will be helpful sometimes - Grothendieck's answer achieves very similar but I like the one line approach.Donaugh
A
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
Accessory answered 27/5, 2014 at 13:22 Comment(10)
There's no other solution? This approach gets really tiresome when many variables need arbitrary renaming... makes helper functions less helpful.Donaugh
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.Accessory
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.Donaugh
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.Accessory
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...Donaugh
No, you are not forced to rename them. I only did that for clarity. helpFunction <- function(importantVar1) importantVar1+1 would work as well.Accessory
it doesn't work for me, can you edit the answer with your suggestion?Donaugh
thanks, I was looking at it the wrong way ;) Still not what I'd like but maybe neater than I have.Donaugh
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?).Accessory
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 :)Donaugh

© 2022 - 2024 — McMap. All rights reserved.