359

I'd like to check if some variable is defined in R - without getting an error. How can I do this?

My attempts (not successful):

> is.na(ooxx)
Error: object 'ooxx' not found
> is.finite(ooxx)
Error: object 'ooxx' not found

Thanks!

Tomas
  • 57,621
  • 49
  • 238
  • 373

7 Answers7

545

You want exists():

R> exists("somethingUnknown")
[1] FALSE
R> somethingUnknown <- 42
R> exists("somethingUnknown")
[1] TRUE
R> 
Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
128

See ?exists, for some definition of "...is defined". E.g.

> exists("foo")
[1] FALSE
> foo <- 1:10
> exists("foo")
[1] TRUE
Gavin Simpson
  • 170,508
  • 25
  • 396
  • 453
69

if you are inside a function, missing() is what you want.

exchequer = function(x) {
    if(missing(x)){
        message("x is missing… :-(")
    }
}

exchequer()
x is missing… :-(
tim
  • 3,559
  • 1
  • 33
  • 46
  • 8
    `missing` only works for function arguments, however. You can't do `foo <- function(x) {missing(x); missing(y)}` or you will get `foo(1)` `> Error in missing(y) : 'missing' can only be used for arguments`. – Dannid Feb 11 '19 at 17:48
61

As others have pointed out, you're looking for exists. Keep in mind that using exists with names used by R's base packages would return true regardless of whether you defined the variable:

> exists("data")
[1] TRUE

To get around this (as pointed out by Bazz; see ?exists), use the inherits argument:

> exists("data", inherits = FALSE)
[1] FALSE

foo <- TRUE
> exists("foo", inherits = FALSE)
[1] TRUE

Of course, if you wanted to search the name spaces of attached packages, this would also fall short:

> exists("data.table")
[1] FALSE
require(data.table)
> exists("data.table", inherits = FALSE)
[1] FALSE
> exists("data.table")
[1] TRUE

The only thing I can think of to get around this -- to search in attached packages but not in base packages -- is the following:

any(sapply(1:(which(search() == "tools:rstudio") - 1L),
           function(pp) exists(_object_name_, where = pp, inherits = FALSE)))

Compare replacing _object_name_ with "data.table" (TRUE) vs. "var" (FALSE)

(of course, if you're not on RStudio, I think the first automatically attached environment is "package:stats")

MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
sbaldrich
  • 1,062
  • 12
  • 15
  • 2
    Playing around, using argument `inherits = FALSE` seems to isolate things in the global environment. Does that sound right? – CJB Jan 07 '16 at 12:49
  • 1
    @Bazz you're correct; I've edited this into the answer. – MichaelChirico Feb 03 '16 at 03:21
  • 3
    This comment should be higher up, since I use variable name "data", just using exist gave me some trouble initially. – mzm May 11 '16 at 14:44
38

If you don't want to use quotes, you can use deparse(substitute()) trick which I found in the example section of ?substitute:

is.defined <- function(sym) {
  sym <- deparse(substitute(sym))
  env <- parent.frame()
  exists(sym, env)
}

is.defined(a)
# FALSE
a <- 10
is.defined(a)
# TRUE
dpel
  • 1,954
  • 1
  • 21
  • 31
Nirmal
  • 667
  • 5
  • 9
  • 1
    you can also `force` or evaluate it in the function like this: `is.defined <- function(sym) class(try(sym, TRUE))!='try-error'` – chinsoon12 Oct 04 '17 at 00:49
  • 2
    this answer may be a tad more complicated...but this is the ideal answer if you don't want to contend with characters vs var-names – Gregg H Jul 12 '20 at 16:37
  • 1
    I have bumped into an issue that needs exactly your solution. When you wanted to use something that's not `NULL` for quosure (`enquo(x)` if x is not null), you need a good way to check if the expression passed in is not null. Your solution does exactly that. thanks – stucash Nov 17 '21 at 16:49
4

If you don't mind using quotes, you can use:

exists("x")

If you don't want to use quotes you can use:

exists(deparse(substitute(x)))

  • This answer combines previous answers. Not sure if this is adding anything to the conversation so far. – Nirmal Nov 15 '21 at 13:29
1

There may be situations in which you do not exactly know the name of the variable you are looking for, like when an array of results have been created by a queuing system. These can possibly be addressed with "ls" and its argument "pattern" that expects a regular expression.

The "exists" function could be reimplemented that way as

exists <-function(variablename) {
   #print(ls(env=globalenv()))
   return(1==length(ls(pattern=paste("^",variablename,"$",sep=""),env=globalenv())))
}

While preparing this answer, I was a bit surprised about the need for the need of the specification of the environment when invoking ls() from within a function. So, thank you for that, stackoverflow! There is also an "all.names" attribute that I should have set to true but have omitted.

smoe
  • 500
  • 3
  • 13