Home > Software engineering >  How to write clean function in R without resorting to GlobalEnv?
How to write clean function in R without resorting to GlobalEnv?

Time:04-12

I have scoured the Internet trying to find a solution and somehow I still can't find a simple, straightforward answer. Maybe it's much more complicated ? I have read Advanced R by Hadley Wickham on lexical scoping but it somehow doesn't help. Maybe I haven't asked the right question, but the answer seems so simple. There's even a chapter in R inferno (Chapter 5.3, Chapter 6) telling me what to do, without really getting into the details while warning against global assignment.

Currently what I'm doing is using Global Assignment which apparently is a disaster. I don't know how to fix my pipeline.

function1 <- function(x){
  x <<- 1
}


function2 <- function(x){
pf <- parent.frame()
if (pf$condition = TRUE){
      result = x   1
    }
else (result = x   2)

function3 <- function(condition = TRUE){
function1()
function2()
}

Let's say my pipeline looks like this. I have two functions, where the second one depends on the result of the first function. I want to eventually access the output of any given function, and to pass it to another one. How do I pass the result of function 1 to result 2, without doing x <<- 1 ?

One workaround I got for passing arguments from a top function to a nested function is using pf <- parent.frame() and using pf$condition to access the parent.frame. However I don't know how to pass a variable to the previous environment (from bottom to top).

This is so I can use conditions, to choose whether or not function 1 and 2 behave differently if they are used together or not (and inside a function that has condition = TRUE). Or maybe I shouldn't do it this way, but I don't know how else I could do that.

There's usage of env = parent.frame() inside the function argument, but I don't know if it will help, because I also want to use function 1 and 2 independently.

CodePudding user response:

The warning not to use global assignment is because it creates a side effect of the function, i.e. calling function1 changes the state of your system/environment (setting the value of x) in places you wouldn't suspect it. This makes it harder to reason about functions and to debug them.

In R, often a rather functional programming approach is used. This means that a function does not have any side effects but only returns a value.

In order to use functions in this way, you have to explicitly assign the return values of functions and declare the arguments of a function. I'd rewrite your functions in the following way:

function1 <- function() {
  1
}

function2 <- function(x, condition) {
  if (condition){
    result <- x   1
  }
  else  {
    result <- x   2
  }
  result
}

function3 <- function(condition = TRUE) {
  f1_res <- function1()
  function2(x = f1_res, condition = condition)
}

function3()
  • Related