Search code examples
rlexical-scope

Difference between <- and <<-


CASE 1:

rm(list = ls())
foo <- function(x = 6){
  set <- function(){
  x <- x*x}
  set()
x}
foo()
# [1] 6

CASE 2:

rm(list = ls())
foo <- function(x = 6){
set <- function(){
  x <<- x*x}
  set()
  x}
foo()
# [1] 36

I read that <<- operator can be used to assign a value to an object in an environment that is different from the current environment. It says that object initialization using <<- can be done to the objects that is not in the current environment. I want to ask which environment's object can be initialized using <<- . In my case the environment is environment of foo function, can <<-initialize the objects outside the function or the object in the current environment? Totally confused when to use <- and when to use <<-.


Solution

  • The operator <<- is the parent scope assignment operator. It is used to make assignments to variables in the nearest parent scope to the scope in which it is evaluated. These assignments therefore "stick" in the scope outside of function calls. Consider the following code:

    fun1 <- function() {
        x <- 10
        print(x)
    }
    
    > x <- 5    # x is defined in the outer (global) scope
    > fun1()
    [1] 10      # x was assigned to 10 in fun1()
    > x
    [1] 5       # but the global value of x is unchanged
    

    In the function fun1(), a local variable x is assigned to the value 10, but in the global scope the value of x is not changed. Now consider rewriting the function to use the parent scope assignment operator:

    fun2 <- function() {
        x <<- 10
        print(x)
    }
    
    > x <- 5
    > fun2()
    [1] 10      # x was assigned to 10 in fun2()
    > x
    [1] 10      # the global value of x changed to 10
    

    Because the function fun2() uses the <<- operator, the assignment of x "sticks" after the function has finished evaluating. What R actually does is to go through all scopes outside fun2() and look for the first scope containing a variable called x. In this case, the only scope outside of fun2() is the global scope, so it makes the assignment there.

    As a few have already commented, the <<- operator is frowned upon by many because it can break the encapsulation of your R scripts. If we view an R function as an isolated piece of functionality, then it should not be allowed to interfere with the state of the code which calls it. Abusing the <<- assignment operator runs the risk of doing just this.