Search code examples
rreturnevalr-environment

call return from child frame


How can I return a value in a function, through another function, see example here :

first_try <- function() eval(return(1),parent.frame())
second_try <- function() source(textConnection("return(2)"),parent.frame())

fun1 <- function(x){
  first_try()
  second_try()
  3
}

fun1()
# [1] 3

fun1 should stop at first_try and return 1, and if second_try had worked it would have returned 2.

Is such a thing possible ?


Solution

  • rlang::return_from() provides this functionality :

    return_a <- function() rlang::return_from(parent.frame(),"a")
    
    fun <- function(){
      return_a()
      "b"
    }
    fun()
    #> [1] "a"
    

    Created on 2020-01-03 by the reprex package (v0.3.0)

    We can also fix my first try by quoting return(1) and use rlang::eval_bare()rather than base::eval()

    From the doc :

    eval_bare() is a lower-level version of function base::eval(). Technically, it is a simple wrapper around the C function Rf_eval(). You generally don't need to use eval_bare() instead of eval(). Its main advantage is that it handles stack-sensitive (calls such as return(), on.exit() or parent.frame()) more consistently when you pass an enviroment of a frame on the call stack.

    first_try <- function() rlang::eval_bare(quote(return(1)),parent.frame())
    fun1 <- function(x){
      first_try()
      second_try()
      3
    }
    
    fun1()
    #> [1] 1
    

    Created on 2020-01-03 by the reprex package (v0.3.0)