Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

variable scope in R tryCatch block: is <<- necessary to change local variable defined before tryCatch?

Consider the following code:

test1 <- "a"
test2 <- "a"
tryCatch(stop(), error= function(err){
  print(test1)
  print(test2)
  test1 <- "b"
  test2 <<- "b"
})

Result:

print(test1)
[1] "a"
print(test2)
[1] "b"

The value of variable test1 is visible within the tryCatch block, but changing it with "<-" operator does not affect its value outside the tryCatch block.

If a new value is assigned with <<- it has the desired effect. Why?

Is using the <<- operator within the tryCatch block a recommended way to change the value of a local variable outside this block? Could there be some unexpected sideffects?

EDIT: Based on a Bernhard answer, does the following code make up for the right approach to this problem?

test1 <- "a"
test2 <- "a"
new_values<-tryCatch(
  {
    print("hello")
    stop()
  }
, error= function(err){
  # I want to change the test1 and test 2 variables to "b" only if error occurred.
  test1 <- "b"
  test2 <- "b"
  return(list(test1=test1,test2=test2))
})
if (is.list(new_values))
{
  test1<-new_values$test1
  test2<-new_values$test2
}

Result:

> print(test1)
[1] "b"
> print(test2)
[1] "b"
like image 405
tomas Avatar asked Jul 20 '16 13:07

tomas


1 Answers

The '<<-' is made for side effects that do not belong to R. Use it never, or only if memory or speed force you to do so. A block has it's own scope and if you want to give data from within a block to the 'outside' environement, that there is return() for that task:

test2 <- "a"

test2 <- tryCatch(stop(), error= function(err){
  somevariable <- "b"
  return(somevariable)
})

This makes it clear to everyone, that toplevel test2 is set to "a" and then, that toplevel test2 is set to something else. With '<<-' it happens easily, that some function changes toplevel test2 and someone wonders, why toplevel test2 has been changed at all. Just don't <<-.

If there is a need to return more than one result, return a list or an object of the results.

EDIT: The OP has pointed out that you need to be carefull with the return statements, as they do not only end the current block, but also the current function. A possible solution is, to run the computations in functions instead of simple blocks. The following example should illustrate this:

safediv <- function(a, b){
    normalDo <- function(a, b){
        return(list(value=a/b, message=NULL))
    }
    exceptionalDo <- function(err){
        return(list(value=NaN, message="caught an error! Change global variable?"))
    }
    results <- tryCatch(normalDo(a, b), error=exceptionalDo)
    print("safediv is still running after the returns within the functions.")
    return(results)
}

# try it out  
safediv(5, 3)
safediv(5, 0)
safediv(5, "a")
like image 177
Bernhard Avatar answered Oct 23 '22 06:10

Bernhard