Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using 'get' Inside Nested Functions on Local Variables

Tags:

function

r

nested

I've never quite gotten my head around nesting functions and passing arguments by reference. My strategy is typically to do something like get('variabletopassbyreference') inside the child function to accomplish this.

Until now, I have been passing global variables to the function and this worked fine. Today I tried to create local variables inside a function and then pass those to a nested function within that function and it failed. I'm unable to get get to work. I also tried tinkering the pos and inherits but to no avail.

I cannot find an exact answer on the net. If I could get this construct to work then that's my preference because I have a bunch of other functions that I've coded up in similar fashion. If I shouldn't be doing this at all and should be doing something else, then that information would be appreciated as well.

An example is below -

test1 <- function(a1,b1) {

  # cat(ls()) # a1 b1
  # cat(ls(pos = 1)) # c test1 test2

  testvalue <- get('c') * get(a1, inherits = TRUE) * get(b1)

  testvalue

}

test2 <- function() {

  a = 1
  b <- 2
  # cat(ls()) # a b
  test1('a','b')

}

c = 3
test2()

I get the following error -

Error in get(a1, inherits = TRUE) : object 'a' not found 

More generic example -

a = 0

test1 <- function(a1,b1) {

  # cat(ls()) # a1 b1
  # cat(ls(pos = 1)) # c test1 test2

  testvalue <- get('c') * a1 * b1

  assign(x = 'a', value = 2.5)
  assign(x = 'a', value = 3.5, envir = parent.frame())
  assign(x = 'a', value = 4.5, envir = .GlobalEnv)
  cat(a)
  cat(' - value of a local within test1\n')
  testvalue

} 

test2 <- function() {

  a = 1
  b <- 2
  # cat(ls()) # a b

  cat(a)
  cat(' - value of a local within test2 before test1 called\n')
  test1(a1 = a, b1 = b)
  cat(a)
  cat(' - value of a local within test2 after test1 called\n')

}
cat(a)
cat(' - value of a global before test 2 \n')
c = 3
test2()

cat(a)
cat(' - value of a global after test 2 \n')
like image 364
TheComeOnMan Avatar asked Dec 25 '22 09:12

TheComeOnMan


1 Answers

Also, pass the environment that the variables are located in. Note that parent.frame() refers to the environment in the currently running instance of the caller.

test1 <- function(a1, b1, env = parent.frame()) {

  a <- get(a1, env)
  b <- get(b1, env)
  c <- get('c', env)

  testvalue <- c * a * b

  testvalue

}

c <- 3
test2() # test2 as in question
## 6

Here a and b are in env c is not in env but it is in an ancestor of env and get looks through ancenstors as well.

ADDED Note that R formulas can be used to pass variable names with environments:

test1a <- function(formula) {
    v <- all.vars(formula)
    values <- sapply(v, get, environment(formula))
    prod(values)
}

test2a <- function() {
    a <- 1
    b <- 2
    test1a(~ a + b + c)
}

c <- 3
test2a()
## 6

REVISION: Corrected. Added comment. Added info on formulas.

like image 52
G. Grothendieck Avatar answered Feb 11 '23 09:02

G. Grothendieck