Scoping Rules of R

When we use some symbol to implement our logics, how does R know which value to assign?

R functions are treated much like any other R objects.

Assume we are running the following code,

> c <- 100 ## Assign a value to 'c'
> (c+1) ## Increment 
[1] 101
> 
> vec <- c(1:10) ## Create a vector
> vec
 [1]  1  2  3  4  5  6  7  8  9 10

If we observe properly, we can still use c() to create vectors. Now the question is how does R know to use which c symbol to use and when? It’s because,

R has separate namespace for functions and non-functions.

Lets try to understand it clearly. When R tried to ‘bind/connect’ a value to a symbol (in our case c(), it search for the corresponding symbol in an order.

  • Search the global environment (workspace) for a symbol name matching the request.
  • Search the namespaces of each of the packages on the search list.

So the search list will have the follow packages (packages which we have loaded) including “.GlobalEnv” as a first item in the search list and the “base” is always at the very end.

> search()
 [1] ".GlobalEnv"        "tools:rstudio"     "package:stats"    
 [4] "package:graphics"  "package:grDevices" "package:utils"    
 [7] "package:datasets"  "package:methods"   "Autoloads"        
[10] "package:base"

“.GlobalEnv” is just our workspace. If there is a symbol matching it will get it from workspace. If nothing found it will search from the rest of the namespace in each of the packages.

Rules of scoping

R uses scoping rules called Lexical scoping (static scoping).

It will determine the value associated with free variable function.

> fun <- function(x,y){
+   x^2 + y / z
+ }
> fun(2,3)

In the above function we have two arguments and they are x, y. But inside the function body we can find another symbol ‘z’. In this case z is called free variable.

According to scoping rules in R it first searches in the environment where the function was defined. An environment is collection of symbols and values. Environments have patents.

> parent.env(globalenv())
<environment: 0x10390d6e0>
attr(,"name")
[1] "tools:rstudio"

Since we defined fun function in global environment, R will look for z in that scope (environment).

> environment(fun) ## to check the scope
<environment: R_GlobalEnv>

These rule are matters because we can define some complex logics and function.

> y <- 10 ## y Symbol
> 
> f1 <- function(x) {
+   y <- 2 ## Binding value to 'y' symbol
+   y^2 + f2(x) ## 'f2' function is used
+ }
> 
> f2 <- function(x) {
+   x * y
+ }
> 
> f1(2) ## Execute 'f1' function 
[1] 24
> f2(2) ## Execute 'f2' fucntion
[1] 20

Blog Series