4

Suppose I have a set of variables x, y that may or may not be defined. These variables get passed into a function called test.

y <- 10
test <- function(a,b) { ifelse(a > b, "hello", "world") }
test(x,y)

# Error in ifelse(a > b, "hello", "world") : object 'x' not found

If I called test(x,y) when x hasn't been instantiated, R will throw an "object 'x' not found" error.

If I add in an exists check, the function works when calling it from a global environment

y <- 10
test <- function(a,b) { 
     print(exists(as.character(substitute(a))))
     if (!exists(as.character(substitute(a)))) {a <- 0}
     ifelse(a > b, "hello", "world")  
}
test(x,y)

# [1] FALSE
# [1] "world"

x <- 11
test(x,y)

[1] TRUE
[1] "hello"

However, if I wrap test(x,y) inside a the blah function. It fails to find the existing variable.

rm(list=ls())
test <- function(a,b) { 
     print(exists(as.character(substitute(a))))
     if (!exists(as.character(substitute(a)))) {a <- 0}
     ifelse(a > b, "hello", "world")  
}
blah <- function() { x <- 11; y <- 10; test(x,y)}
blah()
[1] FALSE -- expecting TRUE
[1] "world" -- expecting "hello"

I'm guessing the failure is due to it not looking in the right environment. Any idea how I can get this working properly?

Shuo
  • 491
  • 1
  • 6
  • 16
  • 1
    Why not use `if(missing(a)) a <- 0` instead of `exists`? That's the proper way to check for missing arguments rather than pulling them in from/trying to locate them in other environments – Rich Scriven Jan 12 '15 at 21:17
  • 1
    @RichardScriven `missing()` only tests if "something" was passed to that parameter. It doesn't check of that think actually points to a valid object. `missing(a)` will return TRUE both when `x` is a variable and when it is not. It would return TRUE for `test(,y)` – MrFlick Jan 12 '15 at 21:23
  • I think your real problem is how you are winding up with code for variables which don't exist. I might rethink the code that leads to such an occurrence. What's the context for this code? – MrFlick Jan 12 '15 at 21:27
  • I'm trying to do a lot of dynamic naming and the using helper functions. Business requirements for the code. – Shuo Jan 12 '15 at 21:30

1 Answers1

5

You can specify in which environment you are looking first:

test <- function(a,b) { 
     print(exists(as.character(substitute(a)), envir=parent.frame()))
     if (!exists(as.character(substitute(a)), envir=parent.frame())) {a <- 0}
     ifelse(a > b, "hello", "world")  
}

This way:

y <- 10
test(x,y)

# [1] FALSE
# [1] "world"

x <- 11
test(x,y)

#[1] TRUE
#[1] "hello"

rm(list=ls())

test <- function(a,b) { 
     print(exists(as.character(substitute(a)), envir=parent.frame()))
     if (!exists(as.character(substitute(a)), envir=parent.frame())) {a <- 0}
     ifelse(a > b, "hello", "world")  
}
blah <- function() { x <- 11; y <- 10; test(x,y)}
blah()

#[1] TRUE
#[1] "hello"
Colonel Beauvel
  • 30,423
  • 11
  • 47
  • 87
  • Thank you. That's what I thought was missing, but couldn't figure out how to get it to look in the parents frame. Is there any better documentation on how environment frames work? I didn't find the R help very useful. – Shuo Jan 12 '15 at 21:27
  • 3
    Hello Shuo, I would recommend you @Hadley 'Advanced R' book, available on the web. He is greatly explainig how envrionnment works in R. And this link contains also some explanations: http://stackoverflow.com/questions/7439110/what-is-the-difference-between-parent-frame-and-parent-env-in-r-how-do-they – Colonel Beauvel Jan 12 '15 at 21:30
  • 1
    @Shuo - I've found the `sys.frame` help page pretty informative. And Hadley's book is very good – Rich Scriven Jan 12 '15 at 21:30