Question

I have a quick function that simply returns a string variable indicating whether or not the inputted tree exists.

buildSpreadTotalDF = function(tree){
  if (exists(as.character(substitute(tree)))){
     ret = "The tree exists"
  }
  else{
     ret = "There tree does not exist"
  }
ret
}

It seems that even if I do

remove(tree)

and check that the object tree does not exist by doing

tree
Error: object 'tree' not found

and even check the boolean statement separately from the function

> exists(as.character(substitute(tree)))
[1] FALSE

if I run the function as

ret = buildSpreadTotalDF(tree)

I will get

ret
[1] "The tree exists"

which seems counter-intuitive. Why would it still enter the first loop of the function when clearly tree does not exist?

Was it helpful?

Solution 2

It is because you named your function argument tree so "tree" will always exist within the function's scope. Instead, pick an argument name that you are unlikely to be using as a variable name, for example:

buildSpreadTotalDF = function(.argh){
   if (exists(as.character(substitute(.argh)))){
      ret = "The tree exists"
   } else{
      ret = "The tree does not exist"
   }
   ret
}

tree <- 1
buildSpreadTotalDF(tree)
# [1] "The tree exists"

remove(tree)
buildSpreadTotalDF(tree)
# "The tree does not exist"

OTHER TIPS

Be precise about where to look for the variable - you want to look in the parent frame, the environment from which your function was called:

tree_exist <- function(var) {
  var_name <- as.character(substitute(var)) 
  if (exists(var_name, envir = parent.frame())){
    "The tree exists"
  }  else {
    "The tree does not exist"
  }
}
tree_exist(tree_exist)
tree_exist(var_name)

The problem is that exists will look in the local scope first (which is the global environment when you just call exists(...) outside your function but is inside your function when called from there. Since tree is the name of the parameter passed to your function, it always exists inside the function. What you probably want to do is to look for your variable in the global environment. You can do this for example by specifying the where parameter, in a slightly modified example from yours, like so:

buildSpreadTotalDF = function(treename){
    if (exists(treename, where = globalenv())){
        ret = "The tree exists"
    }
    else{
        ret = "There tree does not exist"
    }
    ret
}

tree1 <- 1
buildSpreadTotalDF("tree1") # exists
buildSpreadTotalDF("tree2") # does not exist

Correction: I think I was wrong about the default scope of exists(...), see answer above for good advice on just fixing the problem by using an unlikely variable name and the answer below for details on how to get the scoping right.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top