After running:
x <- as.name("aa")
aa <- 2
in R, why doesn't
(x)
return 2? And why doesn't
x <- as.name("aa")
aa <- 3
get(get(x))
return 3?
I know get() expects a string, but I don't understand why it doesn't evaluate x, find the string inside, and then get that. It seems to me like sometimes functions do such evaluation of their arguments, and sometimes they don't. For instance, in the second example, if you replace get(get(x)) with eval(x), eval() evaluates the x to find the name, and then evaluates the name to find 3.
Because the value of x
is not 2, it is the symbol (or name) aa
. However, if you eval
it:
> eval(x)
[1] 2
Similarly, get(x)
doesn't work at all (i.e. produces an error) because as per the documentation for get
, it's first argument must be an object name (given as a character string)
, where the parenthetical is meant to distinguish it from a symbol/name.
get
only works with a character argument:
> get("aa")
[1] 2
And a symbol
(which I find less confusing than name
) is not the same thing:
> identical("aa",as.name("aa"))
[1] FALSE
(as.name
and as.symbol
do the same thing.)
For an excellent explanation of the "evaluation of expressions" vs "evaluation of function arguments" distinction I mention below in a comment, see @MrFlick's answer.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With