Home > Enterprise >  R ensure that `sys.call()` information is always evaluated
R ensure that `sys.call()` information is always evaluated

Time:08-27

I want to use the output of a sys.call() in a function that is being called from a wrapper function. I cannot change the fact that there is a sys.call, but I need to find a way to make the code below function anyway.

We have a top wrapper function, which calls a secondary function, and just a logical statement saved in a variable in the global environment:

test_fun1 <- function(x = hello){
  test_fun2(cond = x)
}

hello <- TRUE

So let's look at this secondary function and define it like this and execute it:

Case 1

test_fun2 <- function(cond){
  call <- sys.call()
  call$cond
}

So when I evaluate the test_fun1 with the value stored in the hello variable:

test_fun1(hello)

I do not get the evaluated value of the hello value but it gives me the output:

x

Case 2

Now when I use the eval() function with its default, I get an error that the variable x is not found:

# Case 2
test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond)
}

test_fun1(hello)
> Error in eval(call$cond) : object 'x' not found

Case 3

So it's clear that I need to deal with the different environments. So I modify the option in the eval function:

test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond, envir = 1)
}

test_fun1(hello)
TRUE

New challenge for Case 3

But now when you wrap the wrapper function in yet another function, this approach does not work again either:

test_fun3 <- function(y){
  test_fun1(x = y)
}

test_fun3(y = hello)

And we would need:

Solution for new problem with case 3

test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond, envir = 2)
}
test_fun3(y = hello)

Now here is essentially my question: Can I automate this envir (or use a different way to evaluate the call) argument so that the call argument is always evaluated, no matter how many functions are called above it?

Many thanks

Full code

test_fun1 <- function(x = hello){
  test_fun2(cond = x)
}

hello <- TRUE

# Case 1
test_fun2 <- function(cond){
  call <- sys.call()
  call$cond
}

test_fun1(hello)

# Case 2
test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond)
}

test_fun1(hello)



# Case 3
test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond, envir = 1)
}

test_fun1(hello)



# Problem with Case 3
test_fun3 <- function(y){
  test_fun1(x = y)
}

test_fun3(y = hello)


# Solution for Problem with Case 3
test_fun2 <- function(cond){
  call <- sys.call()
  eval(call$cond, envir = 2)
}
test_fun3(y = hello)

CodePudding user response:

Can I automate this envir (or use a different way to evaluate the call) argument so that the call argument is always evaluated, no matter how many functions are called above it?

seems like you are wanting to set an environment number one less the length of the current stack length.

  eval(call$cond, envir = length(sys.calls()) -1 )

CodePudding user response:

Another option is to use dynGey(deparse(call$cond)). It will look the variable in call$cond up going through the environments in the call stack. This might have unwanted effects.

# Case 3
test_fun2 <- function(cond){
  call <- sys.call()
  dynGet(deparse(call$cond))
}
  •  Tags:  
  • r
  • Related