Base R has a function get()
that searches for a given name over the environment stack and returns its value after finding it. For example, we can use it like this.
x = 9
get("x")
## [1] 9
get("mean") # inherits is set to TRUE by default
## function (x, ...)
## UseMethod("mean")
## <bytecode: 0x7fa52b0c08a0>
## <environment: namespace:base>
get("mean", inherits = FALSE)
## Error in get("mean", inherits = FALSE): object 'mean' not found
mean = function() "fake mean"
get("mean")
## function() "fake mean"
If you don’t understand why they returned the values they did, you can learn how environment works by reading this post.
We can write our own version of get() using recursion. First we write a helper function that works the same as get(name, inherits = T)
.
get_helper = function(name, env = parent.frame()) {
# Returns the value that name binds to. Looks for name in the given
# environment and all its parents.
# name: string, name of an object
# env : environment object where the search begins. Default value is
# the global environment
if (identical(env, emptyenv())) { # base case
stop("object '", name, "'", " not found", call. = F)
} else if (exists(name, envir = env, inherits = F)) { # success case
env[[name]]
} else { # recursive case
get_helper(name, parent.env(env))
}
}
get_helper("x")
## [1] 9
get("mean")
## function() "fake mean"
Next we can easily extend it to a more general version that takes an additional parameter inherits
.
get_gmlang = function(name, env=parent.frame(), inherits = T) {
# Returns the value that name binds to. If inherits = T, looks for name
# in the given environment and all its parents. Otherwise, looks
# for name only in the given environment.
#
# name: string, name of an object
# env : environment object where the search begins. Default value is
# the global environment
# inherits: logical
if (inherits) {
get_helper(name, env)
} else if (exists(name, envir = env, inherits = F)) {
env[[name]]
} else {
stop("object '", name, "'", " not found", call. = F)
}
}
e = new.env()
e$z = 100
get_gmlang("x", env=e, inherits = T)
## [1] 9
get_gmlang("x", env=e, inherits = F)
## Error: object 'x' not found
get_gmlang("z", env=e)
## [1] 100
get_gmlang("z") # note: global environment is the parent of e
## Error: object 'z' not found
Moreover, we can easily extend get_helper()
to a function fget_helper()
that finds only function objects.
fget_helper = function(name, env = parent.frame()) {
# Returns the value that name binds to when name binds to a function.
# Looks for name in the given environment and all its parents.
#
# name: string, name of an object
# env : environment object where the search begins. Default value is
# the global environment
if (identical(env, emptyenv())) { # base case
stop("Can't find ", name, " as a function object", call. = F)
} else if (class(env[[name]]) == "function") { # success case
# if name not in env, env[[name]] returns NULL with class "NULL"
env[[name]]
} else { # fail case
fget_helper(name, parent.env(env))
}
}
fget_helper("x")
## Error: Can't find x as a function object
fget_helper("mean")
## function() "fake mean"
rm("mean")
fget_helper("mean")
## function (x, ...)
## UseMethod("mean")
## <bytecode: 0x7fa52b0c08a0>
## <environment: namespace:base>