Search code examples
rreturnenvironment

Push return to parent function


Is there a way how to force parent function to return an output? Say I have a function that 'does something' and at the beginning of each function a want to 'check something'. If the check fails I want to return 'something else'.

In my example below 'does something' is logarithm, 'check something' means checking that the variable is nonnegative and 'something else' is minus infinity.

weird_log <- function(x) {
  check(x)
  log(x)
}

check <- function(x) {
  if (x <= 0)
    eval.parent(parse(text = 'return(-Inf)'))
}

This example doesn't work

weird_log(10)  # 2.302585
weird_log(-10) # NaN

One solution is to return 'something else' from the check function if the checks find a problem and NULL otherwise. Then I can write one if in the parent function and it's done.

weird_log <- function(x) {
  y <- check(x)
  if (!is.null(y)) return(y)
  log(x)
}

check <- function(x) {
  if (x <= 0) {
    -Inf
  } else {
    NULL
  }
}

This solution still keeps most of the functionality in separated function check() but is there a way to have all the functionality in it?


In the real problem the checking function does more than just one comparison and it is used in multiple functions so it is necessary to have it separately. Also 'something else' that returns the check function depends on condition which the input fails.


More realistic example:

weird_log <- function(input) {
  y <- check(input)
  if (!is.null(y)) return(y)
  list(log = log(input$x))
}

check <- function(input) {
  if (is.null(input$x)) {
    list(error = 'x is missing')
  } else if (!is.numeric(input$x)) {
    list(error = 'x is not numeric')
  } else if (x <= 0) {
    list(log = -Inf, warn = 'x is not positive')
  } else {
    NULL
  }
}

Solution

  • Because the answer does not actually answer the question here is how to do what you asked.

    returnFromParent <- function() {
      call <- rlang::expr(return()) 
      rlang::eval_bare(call, env = parent.frame())
    }
    
    foo <- function(){
      returnFromParent()
      print("you should not see this")
    }
    
    foo()
    

    The only way I have found to do this is using rlang.