Skip to content

A where() functions that does what exists() does but return the environment when object lives?

7 messages · Henrik Bengtsson, Uwe Ligges, Hadley Wickham

#
Hi,

exists("foo", inherits=TRUE) check whether an object named "foo"
exists, and get("foo", inherits=TRUE) retrieves it.  I'm looking for a
similar function to exists() that returns the environment where the
object "foo" exists, iff at all.  If not found, NULL is returned.
Does that exist?

EXAMPLE #1:
<environment: R_GlobalEnv>

Note the difference to:
<environment: namespace:base>


EXAMPLE #2:
$a
<environment: R_GlobalEnv>
$b
<environment: 0x000000000b7d2798>
$a
<environment: R_GlobalEnv>
$b
<environment: 0x000000000b7d23e0>


I do understand that I can implement such a function myself, but I
prefer not to.

Thanks,

Henrik
#
I'd start looking at getAnywhere().

Best,
Uwe
On 10.10.2015 01:18, Henrik Bengtsson wrote:
3 days later
#
On Sat, Oct 10, 2015 at 1:24 AM, Uwe Ligges
<ligges at statistik.tu-dortmund.de> wrote:
Thanks Uwe, that does indeed provides "where" information.
Unfortunately, I don't see how it will allow me to search environments
similarly/in the same order as exists/get(..., envir, inherits=TRUE)
does it.  getAnywhere() will search everything in any order.  It's a
start though.

Cheers,

Henrik
#
Seems easy enough to write yourself:

where <- function(x, env = parent.frame()) {
    if (identical(env, emptyenv()))
        return(NULL)
    if (exists(x, envir = env, inherits = FALSE))
        return(env)
    where(x, parent.env(env))
}

sample2 <- base::sample
where("sample2")
#> <environment: 0x1154d3c28>
where("sample")
#> <environment: base>
where("blah")
#> NULL

Hadley

On Fri, Oct 9, 2015 at 6:18 PM, Henrik Bengtsson
<henrik.bengtsson at ucsf.edu> wrote:

  
    
#
On Tue, Oct 13, 2015 at 4:43 PM, Hadley Wickham <h.wickham at gmail.com> wrote:
And that returns a random environment because I ran it with
reprex::reprex().  In interactive use it will return <environment:
R_GlobalEnv>

Hadley
#
On 13.10.2015 22:39, Henrik Bengtsson wrote:
Ah, in the same order.... Then you probably need to write some code, but 
sources of the existing functions should allow for a good start, I believe.

Good luck,
Uwe
#
Thanks Uwe and thanks Hadley.  I ended up implementing:

## Emulates R internal findVar1mode() function
## https://svn.r-project.org/R/trunk/src/main/envir.c
where <- function(x, where=-1, envir=if (missing(frame)) { if (where <
0) parent.frame(-where) else as.environment(where) } else
sys.frame(frame), frame, mode="any", inherits=TRUE) {
  tt <- 1
  ## Validate arguments
  stopifnot(is.environment(envir))
  stopifnot(is.character(mode), length(mode) == 1L)
  inherits <- as.logical(inherits)
  stopifnot(inherits %in% c(FALSE, TRUE))

  ## Search
  while (!identical(envir, emptyenv())) {
    if (exists(x, envir=envir, mode=mode, inherits=FALSE)) return(envir)
    if (!inherits) return(NULL)
    envir <- parent.env(envir)
  }

  NULL
}

Here where() provides the same arguments as exists() and get().  It
turns out one needs to tweak the default value for 'envir' argument in
order work the same.

One could argue that where() should always return an environment, i.e.
it should return emptyenv() instead of NULL if the object was not
found.  On the other hand, it's easier to test for is.null(env) than
identical(env, emptyenv()).

/Henrik
On Tue, Oct 13, 2015 at 2:44 PM, Hadley Wickham <h.wickham at gmail.com> wrote: