eval
vs get
I’ve been fighting damn scoping issues lately and finally sat down to figure out what works and when. Documenting some of them here
The lessons I’ve learned from this:
eval(a, envir = … )
DOES NOT WORK!
eval(str2lang(“a”), envir = …)
eval.parent(a)
DOES NOT WORK!
eval.parent(str2lang(“a”))
works and SKIPS GENERIC!
get(“a”, envir = …)
seems to always work as expected
So to summarize, I think get
is always a safer option than
eval
. In addition, get
is much faster:
f1 <- function() {
eval.parent(str2lang("a"))
}
f2 <- function() {
get("a", envir = sys.frame(0))
}
a <- 1
microbenchmark:::microbenchmark(f1(), f2(), times = 10000)
## Unit: nanoseconds
## expr min lq mean median uq max neval
## f1() 1189 1271 1533.3836 1312 1353 1023401 10000
## f2() 492 574 683.9497 574 615 499544 10000
Obviously this doesn’t cover more advanced situations, like evaluating full calls, but I’m still working on puzzling all that out.
Here’s the sample code I used to evaluate this:
foo <- function(x) {
cat("In foo\n")
a <- "in generic"
UseMethod("foo")
}
foo.numeric <- function(x) {
cat("In foo.numeric\n")
a <- "in specific"
# Itself
print(paste("a:",
a
))
# Eval
print(paste("eval(a):",
eval(a)
))
print(paste('eval(str2lang("a")):',
eval(str2lang("a"))
))
# eval.parent
print(paste("eval.parent(a):",
eval.parent(a)
))
print(paste('eval.parent(str2lang("a")):',
eval.parent(str2lang("a"))
))
# eval with sys.frames
print(paste("eval(a, envir = sys.frame(0)):",
eval(a, envir = sys.frame(0))
))
print(paste('eval(str2lang("a"), envir = sys.frame(0)):',
eval(str2lang("a"), envir = sys.frame(0))
))
print(paste("eval(a, envir = sys.frame(1)):",
eval(a, envir = sys.frame(1))
))
print(paste('eval(str2lang("a"), envir = sys.frame(1)):',
eval(str2lang("a"), envir = sys.frame(1))
))
# get
print(paste('get("a"):',
get("a")
))
# get with sys.frames
print(paste('get("a", envir = sys.frame(0)):',
get("a", envir = sys.frame(0))
))
print(paste('get("a", envir = sys.frame(1)):',
get("a", envir = sys.frame(1))
))
}
a <- "in global"
foo(1)
## In foo
## In foo.numeric
## [1] "a: in specific"
## [1] "eval(a): in specific"
## [1] "eval(str2lang(\"a\")): in specific"
## [1] "eval.parent(a): in specific"
## [1] "eval.parent(str2lang(\"a\")): in global"
## [1] "eval(a, envir = sys.frame(0)): in specific"
## [1] "eval(str2lang(\"a\"), envir = sys.frame(0)): in global"
## [1] "eval(a, envir = sys.frame(1)): in specific"
## [1] "eval(str2lang(\"a\"), envir = sys.frame(1)): in global"
## [1] "get(\"a\"): in specific"
## [1] "get(\"a\", envir = sys.frame(0)): in global"
## [1] "get(\"a\", envir = sys.frame(1)): in global"
Home |
Back to blog
This work is licensed under
CC BY-NC 4.0