Reputation: 1058
According to the document
Substitution takes place by examining each component of the parse tree as follows: If it is not a bound symbol in env, it is unchanged. If it is a promise object, i.e., a formal argument to a function or explicitly created using delayedAssign(), the expression slot of the promise replaces the symbol. If it is an ordinary variable, its value is substituted, unless env is .GlobalEnv in which case the symbol is left unchanged.
So I did some experiments
a = 10
# first
f1 = function(x){
substitute(x)
}
f1(a)
# [1] a
# second
f1 = function(x){
x
substitute(x)
}
f1(a)
# [1] a
# third
f1 = function(x){
force(x)
substitute(x)
}
f1(a)
# [1] a
# fourth
f1 = function(x){
x = x
substitute(x)
}
f1(a)
# [1] 10
In the second and third experiments, I supposed that x was not a promise anymore, so substitute
should return 10
instead of a
. But it still returned a
. Why?
Upvotes: 1
Views: 168
Reputation: 132576
From the language definition:
Until that argument is accessed there is no value associated with the promise. When the argument is accessed, the stored expression is evaluated in the stored environment, and the result is returned. The result is also saved by the promise. The substitute function will extract the content of the expression slot. This allows the programmer to access either the value or the expression associated with the promise.
A promise stays a promise even if its expression has been evaluated. You can see what happens with the pryr package:
library(pryr)
f=function(x){
print(promise_info(x))
force(x)
promise_info(x)
}
a <- 10
f(a)
#$code
#a
#
#$env
#<environment: R_GlobalEnv>
#
#$evaled
#[1] FALSE
#
#$value
#NULL
############################
#$code
#a
#
#$env
#NULL
#
#$evaled
#[1] TRUE
#
#$value
#[1] 10
Obviously, assigning a new value to the symbol replaces the promise with that value. That's what happens in your last function.
Upvotes: 1