I think @joran's answer is right but maybe I can try to explain a different way.
The (
"function" in R is essentially the identity function. It echoes back what you pass it. It's almost like it isn't there. There is no difference between what will be returned by these statements
x #1
(x) #2
((x)) #3
The parenthesis just passthrough the value inside. You can add as many parenthesis as you want and it will not change what's returned. The evaluator looks at ((x))
, see the outer parenthesis, and knows to just return the value of the thing inside the parenthesis. So now it's parsing just (x)
, and again, it sees the outer parenthesis and will just return the value inside the parenthesis, which is x
. The parenthesis just pass though the value from the inside; they do not evaluate it.
The bare value x
is a name (or symbol). A name is not uniquely tied to a value. The mapping between names and values differs by environment. That's why names must be evaluated in a particular context to get a value. Consider these examples
aa <- 5
dd <- data.frame(aa=20)
x <- as.name("aa")
foo <- function(x) {aa<-10; eval(x)}
eval(x)
# [1] 5
foo(x)
# [1] 10
eval(x, dd)
# [1] 20
This behavior is actually highly desirable. It's what makes features that require non-standard evaluation work, like
subset(mtcars, hp<100)
When you are using the R console, it behaves as a REPL -- it reads your input, evaluates it, prints it, and then waits for the next input. Note that it only does one level of evaluation and the evaluation happens in the "current" environment. It does not recursively evaluate the returned value from an expression. So when you do
x <- as.name("aa")
x # identical to (x)
# aa
when the REPL gets to the evaluation step, it evaluates the name x
which points to the name aa
. That's it. One level of evaluation. The name aa
is not subsequently evaluated.
There is a note in the ?eval
help page that says this:
eval evaluates its first argument in the current scope before passing it to the evaluator
There's not a "double" evaluation happening there. It is merely evaluating it's parameters just as any other function in R does. For examples
aa <- 5
bar <- function(x) print(x)
bar(aa+2)
# [1] 7
It prints "7", not "aa+2" because the function has evaluated it's parameter prior to printing. It also explains the differences between these two
dd <- data.frame(bb=20)
xx <- as.name("bb")
eval(bb, dd)
# Error in eval(bb, dd) : object 'bb' not found
eval(xx, dd)
# [1] 20
In the first eval()
call, R is unable to evaluate bb
in the current environment so you get the error. But note that
evalq(bb, dd)
does work because evalq
does not try to evaluate the first expression parameter.
get
do whateval
does, but then the answer would have to be because they do two different things: one evaluates an expression (which may be a symbol) and the other retrieves objects where you specify the name (symbol) of the object via a character. Why wouldn't you split different functionality into two different functions? – Sensuality