I'm trying to create a function that references the scope from which it was called to create a unique ID:
uniqueid <- function(name, envir = NULL) {
if(identical(envir, globalenv())) {
e = envir
} else if (is.null(envir)) {
e = parent.frame()
} else if (is.environment(envir)) {
e = envir
} else {
stop("given non-default argument \'envir\' is not an environment")
}
return(paste(sep = "",
sub('<environment: (.*)>', '\\1', capture.output(e)),
".",
name
)
)
}
What can I do to make this work the way I think it should work? R keeps returning the scope in which the function was defined, and not where it is evaluated:
hello <- new.env()
hello$env <- new.env()
eval(envir=hello$env, {
print(environment())
print(hello$env) #hello$env is an environment
print(hello) #hello is an environment
uniqueid('hi')
})
I'm trying to get at least one of these to match up, but it doesn't seem like it wants to work. R either returns the global environment, or the ever-changing scope of a temporary frame/environment created for an instance of a call to the function. The ID needs to be reproducible between multiple calls and dependent on the environment.
I know I could pass the environment, but I'm beginning to wonder whether doing capture of the caller's environment is actually possible.
Your problem is that
eval()
expects something that is unevaluated. By passing in a code block{}
, you are not preventing evaluation. For example, consider the simpler caseNotice how the last two either explicitly quote the expression, or use
evalq()
to do the quoting of the expression. These allow the evaluation to be delayed until executed inside the requested environment.So if you just change your
eval()
toevalq()
, you should be fine.TL,DR:
parent.frame()
notparent.frame(environment())
;evalq
noteval
.parent.frame
takes argumentn
being number of generations to go back, not the result of anenvironment()
call (which is an environment). If you leave it out of theparent.frame()
call you're fine.Also, yoru example code doesn't work as you expect, because your
environment()
command is being evaluated in the call toeval
, before being evaluated as part ofeval
. I.e. you must quote your argument toeval
. Alternatively, useevalq
rather thaneval
.E.g.
E.g. this will get the environment ID and add it to the
name
: