## Variable scope

The outside environment can't peak into functions:

f1 <- function(a, b) {
a + b
}

f1(10 , 20)
## [1] 30
a <- 11
a
## [1] 11
f1(10, 20)
## [1] 30

But functions can reach up to the outside:

c <- 100

f2 <- function(a, b) {
a + b + c
}

f2(10, 20)
## [1] 130
c <- 200
f2(10, 20)
## [1] 230
c  <- 100
f3 <- function(d) {
function(a, b) {
a + b + c + d
}
}

In this case our f3 is a functin that returns a function (so meta).

f3(10)
## function(a, b) {
##     a + b + c + d
##   }
## <environment: 0x4efa8f8>
f4 <- f3(1)
f4(10, 20)
## [1] 131
f5 <- f3(2)
f5(10, 20)
## [1] 132

This would be an equivalent of the last line (even if it is a bit iffy):

f3(2)(10, 20)
## [1] 132

## Pass-by-value and immutability

Let's see it in action:

c  <- 100
f6 <- function(a, b) {
print(c)
c <- 200
print(c)

a + b + c
}
f6(10, 20)
## [1] 100
## [1] 200
## [1] 230
c
## [1] 100

Here's an example that might be surprising for folks who have worked in other dynamic languages:

l  <- list(a = 10, b = 20)
f7 <- function(mutantList) {
mutantList$c <- 30 mutantList } f7(l) ##$a
## [1] 10
##
## $b ## [1] 20 ## ##$c
## [1] 30
l
## $a ## [1] 10 ## ##$b
## [1] 20

## And now for something crazy: being lazy

area <- function(l, w = l) {
l * w
}
area(2, 3)
## [1] 6
area(2)
## [1] 4

Python would not have been cool with that.

So you can do things like this:

area <- function( l
, w = if (square) { l }
, square = if (l == w) { TRUE } else { FALSE }
) {

if (square) { print("It's a square!") }

l * w
}
area(2, 3)
## [1] 6
area(2, 2)
## [1] "It's a square!"
## [1] 4
area(2, square = TRUE)
## [1] "It's a square!"
## [1] 4

This is either really awesome or totally insane, depending on perspective.