Reputation: 2321
In the code below, I expect both f and the final a to return 3. But in fact they both return 2. Why is this? Hasn't 3 replaced 2 in the enclosing environment at the time the promise is evaluated?
a <- 1
f <- function(a){
a <<- 3
cat(a)
}
f(a <- 2)
a
Note that If I use an = instead of a <- in the call to f, the final a is 3 as expected, but f remains 2.
Upvotes: 0
Views: 43
Reputation: 206197
Let's walk through the code
a <- 1
assigns the value 1 to the name a
in the global environment.
f <- function(a){...}
creates a function saved to the name f
in the global environment.
f(a <- 2)
Now we are calling the function f
with the expression a<-2
as a parameter. This expression is not evaluated immediately. It is passed as a promise. The global value of a
remains 1.
Now we enter the body of the function f
. The expression we've passed in is assigned to the local variable a
in the function scope (still un-evaluated) and a
in the global remains 1. The fact they they both involve the symbol a
is irrelevant. There is no direct connection between the two a
variables here.
a <<- 3
This assigns the value of 3 to a in a parent scope via <<-
rather than the local scope as <-
would do. This means that the a
refered to here is not the local a
that now hold the parameter passed to the function. So this changes the value of a
in the global scope to 3. And finally
cat(a)
Now we are finally using the value that was passed to the function since the a
here refers to the a
in the local function scope. This triggers the promise a <- 2
to be run in the calling scope (which happens to be the global scope). Thus the global value of a
is set to 2. This assignment expression returns the right-hand-side value so "2" is displayed from cat()
.
The function exits and
a
shows the value of the a
in the global environment which is now a
. It was only the value 3 in the brief moment between the two expressions in f
.
If you where to call
f( a=2 )
This is very different. Now we are not passing an expression to the function anymore, we are passing the value 2 to the named function parameter a
. If you tried f(x=2)
you would get an error that the function doesn't recognize the parameter named "x". There is no fancy lazy expression/promise evaluation in this scenario since 2 is a constant. This would leave the global value set to 3 after the function call. f(a <- 2)
and f(a = a <- 2)
would behave the same way.
Upvotes: 2