Hierarchy of Scope in R
Lexical Scope
R uses lexical scope, meaning that variables are resolved based on the environment where they were defined. Each function captures its defining environment and can access it even after the function has completed execution.
Scope Hierarchy
When a variable is used in R, it is resolved according to a specific hierarchy of environments. Here’s the order in which R looks for a variable:
Local Scope
- Function Environment: R first looks for the variable in the local environment of the function where it is used. If the variable is found, it is used directly.
my_function <- function() { local_var <- 10 print(local_var) # local_var is found in the function's environment } my_function() # Prints 10
Parent Environment
- Function Definition Environment: If the variable is not found in the function’s local environment, R looks in the environment where the function was defined, known as the parent environment.
x <- 5 my_function <- function() { print(x) # x is found in the parent environment } my_function() # Prints 5
Global Environment
- Global Environment: If the variable is not found in the function’s environment or its parent environment, R searches in the global environment, which is the top-level environment where global variables are defined.
y <- 100 another_function <- function() { print(y) # y is found in the global environment } another_function() # Prints 100
Package Environments
- Package Environments: If the variable is not found in the local, parent, or global environments, R may look in package environments, which are environments created by loaded packages.
Illustrative Example of Scope Hierarchy
Here’s an example showing how R resolves variables according to the scope hierarchy:
global_var <- "Global" outer_function <- function() { outer_var <- "Outer" inner_function <- function() { inner_var <- "Inner" print(inner_var) # 1. Looks in the local environment of inner_function print(outer_var) # 2. Looks in the parent environment (outer_function) print(global_var) # 3. Looks in the global environment } inner_function() } outer_function()
In this example:
- inner_var is found in the local environment of inner_function.
- outer_var is found in the parent environment (outer_function).
- global_var is found in the global environment.
Using <<- and assign()
<<- for Modifying Global Variables
The double arrow operator <<- allows you to modify global variables from within a function.
global_var <- 1 update_global <- function() { global_var <<- 10 } update_global() print(global_var) # Prints 10
assign() for Variable Modification
The assign() function can also be used to modify variables in specific environments.
my_env <- new.env() assign("var_in_env", 42, envir = my_env) print(my_env$var_in_env) # Prints 42
Scope and Closures
Functions in R can create closures that capture variables from their defining environment even after that environment has finished execution.
make_counter <- function() { count <- 0 function() { count <<- count + 1 return(count) } } counter <- make_counter() print(counter()) # Prints 1 print(counter()) # Prints 2
Summary
- Local Scope: R first looks in the function’s local environment.
- Parent Environment: If not found, R searches in the environment where the function was defined.
- Global Environment: R then looks in the global environment.
- Package Environments: Finally, R may search in package environments.
- Closures: Functions capture and use variables from their defining environment.