deschen
deschen

Reputation: 10996

Function should not return a value if it doesn't exist in the function

I'm writing a function that contains some conditions. The returning value of the function will depend on such a condition in a way that the returning value might not even exist within the function based on the condition. In that case, I'd expect the function to throw an error. However, this only works as long as the supposed-to-return value does not also exist in the global environment. If it does, the value from the global environment is returned, which I find confusing.

What am I missing here? What am I doing wrong?

Example:

xyz <- function(x = NULL, y = NULL)
{
  if (x+y > 10) {z <- x + y}

  return(z)
}

If I now run test <- xyz(20, 30) I get the correct result (test = 50). If I run test <- xyz(2, 3) I also correctly get an error:

Error in xyz(2, 3) : object 'z' not found

However, now I'm creating a z value in the global environment.

z <- 3.14

When I'm now running my function test <- xyz(2, 3) I get 3.14 as the result.

I was expecting that the function will only return the value of z if it exists inside the function. How can I do that?

Thanks

Upvotes: 0

Views: 654

Answers (3)

G. Grothendieck
G. Grothendieck

Reputation: 269431

If a free variable (one referred to but not defined) in a function is accessed then it looks in the environment where the function was defined and then in the parent environment of that and so on.

Use get("z", inherits = FALSE) to look for z only in the current environment or check whether it exists exists("z", inherits = FALSE) in the current environment only.

Another possibility is to always give z a value:

z <- if (length(x) && length(y) && x + y > 10) x + y

In that case z will have the value NULL if the condition is false because the default else leg is NULL. Returning NULL invisibly would be about as close as you can get to not returning a value.

xyz2 <- function(x = NULL, y = NULL) {
  z <- if (length(x) && length(y) && x + y > 10) x + y
  # other processing can go here
  if (is.null(z)) invisible(z) else z
}
xyz2(1, 2)
xyz2(5, 9)
## [1] 14

Upvotes: 3

Gregor Thomas
Gregor Thomas

Reputation: 145755

I like duckmayr's idea, but here's how you can implement while still using z:

xyz <- function(x = NULL, y = NULL) {
    z = x + y
    if (z <= 10 ) {
        stop("The sum of x and y must be greater than 10.")
    }
    return(z)
}

Upvotes: 2

duckmayr
duckmayr

Reputation: 16910

Why not just throw an informative error, based on the condition rather than z?

xyz <- function(x = NULL, y = NULL)
{
    if ( x + y <= 10 ) {
        stop("The sum of x and y must be greater than 10.")
    }
    return(x + y)
}

xyz(20, 30)
# [1] 50
xyz(2, 3)
# Error in xyz(2, 3) : The sum of x and y must be greater than 10.

Upvotes: 3

Related Questions