0

It looks like you can have one function pass data back transparently to a parent function with the assign operation.

Example (Setup)


calling = function()
    {
    a = 25;
    cat("\n ...CALLING... a = ", a, "\n");
    assign("a", a, envir=parent.frame(1) );  # ?sys.calls
    }


caller = function()
    {
    a = 15;
    cat("\n ...CALLER... a = ", a, "\n");
    
    pf = parent.frame(); ## how to say THIS current FRAME
    cat("\n ...CALLER_FRAME... pf = \n");
    print(pf);
    
    cat("\n\n\n");
    
    calling();
    cat("\n ...CALLER*... a = ", a, "\n");
    }

RUN

a = 5;
cat("\n ...GLOBAL... a = ", a, "\n");
caller();
# scope, should mess with GLOBAL = 5
cat("\n ...GLOBAL*... a = ", a, "\n");

OUTPUT

> a = 5;
> cat("\n ...GLOBAL... a = ", a, "\n");

 ...GLOBAL... a =  5 
> caller();

 ...CALLER... a =  15 

 ...CALLER_FRAME... pf = 
<environment: R_GlobalEnv>




 ...CALLING... a =  25 

 ...CALLER*... a =  25 
> # scope, should mess with GLOBAL = 5
> cat("\n ...GLOBAL*... a = ", a, "\n");

 ...GLOBAL*... a =  5 

Question

So above, the GLOBAL a was not altered, but calling was able to update the value of a for caller without returning the value. That is, calling passed back the value to caller with assign.

The question is in the code, in caller, how do I get THIS current frame reference?

How could I use that if I had more complicated nesting? Pass envir to calling that may have been a few functions deep? This reference Can you pass-by-reference in R? has some discussion, but I don't fully under THIS current frame reference of caller?

Dharman
  • 30,962
  • 25
  • 85
  • 135
mshaffer
  • 959
  • 1
  • 9
  • 19
  • 3
    Are you just trying to get the current environment? `environment()` with no arguments will return the current environment. If that’s not what you want, can you clarify you question by providing expected output? – zephryl Aug 15 '22 at 17:28
  • 1
    R is not C, in `instruction;` the semi-colon is the instruction separator. `instruction;` is *two* instructions, `instruction; NULL`. – Rui Barradas Aug 15 '22 at 17:32

1 Answers1

1

As @zephryl said, environment() returns the currently active environment. You could write your calling() function like this:

calling <- function(envir = parent.frame()) {
  a <- 25
  assign("a", a, envir = envir)
}

and then it would by default assign in the caller, but if you specified the envir argument it could assign there instead.

Then you could do something like this:

myenv <- new.env()
calling(envir = myenv)
myenv$a
#> [1] 25

to do the assignment in a custom environment. And if you wrote caller() like this:

caller <- function() {
  a <- 2
  calling(envir = environment())
  cat("in caller, a=", a, "\n")
}
a <- 1
caller()
#> in caller, a= 25
print(a)
#> [1] 1

it would work just like

caller2 <- function() {
  a <- 3
  calling()
  cat("in caller2, a=", a, "\n")
}

a <- 4
caller2()
#> in caller2, a= 25
print(a)
#> [1] 4

because while evaluating caller(), environment() gives a reference to the active environment, and while evaluating calling(), parent.frame() points to the environment of the caller, which would be the same thing.

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • I am trying to avoid create a new env, one to build on the base. So `environment()` and `parent.frame(1)` and `parent.frame()` are all the same thing? – mshaffer Aug 16 '22 at 18:43
  • No. The last two are the same, but `environment()` is different. It just happens to give the same value as `parent.frame()` in the context described. – user2554330 Aug 16 '22 at 20:38