Arguments and local variables

9.0.13 Call by value vs call by reference

functions cannot change the state of their arguments

test_change <- function(y)
{
    y[1] <- 7
    y
}

x <- 1:5
test_change(x)
## [1] 7 2 3 4 5
print(x) 
## [1] 1 2 3 4 5

9.0.14 Variable scope

Function arguments and any other variables we create inside a function’s body are relative to each call to that function.

test_change <- function(x)
{
    x <- x+1
    z <- -x
    z
}

x <- 1:5
test_change(x*10)
## [1] -11 -21 -31 -41 -51
print(x)  # x in the function's body was a different x
## [1] 1 2 3 4 5
#print(z)
## Error in eval(expr, envir, enclos): object 'z' not found

Important note:

  • do not refer to object not passed has an argument

  • it is the function call that is producing the local scope not {}

9.0.15 Closures

  • Most user defined function are “closures”.
x <- seq(0, 1, length.out=11)
f1 <- approxfun(x, x^2)
f2 <- approxfun(x, x^3)
print(f1)
## function (v) 
## .approxfun(x, y, v, method, yleft, yright, f, na.rm)
## <bytecode: 0x55aa10994f18>
## <environment: 0x55aa109a1268>
print(f2)
## function (v) 
## .approxfun(x, y, v, method, yleft, yright, f, na.rm)
## <bytecode: 0x55aa10994f18>
## <environment: 0x55aa10ad2ed0>

They look the same but they carry different data!

9.0.16 Default arguments

We already see plenty of them (the book use log).

  • round : digits = 0

  • hist : I quickly counted 10 of them

  • grep : 6 of them

  • download.file: at least 4 and maybe more depending on extra (NULL here)

Default arguments can be constants but also R expressions.

Usually at the end of list of parameters.

9.0.17 Lazy versus eager evaluation

Function argument are valuated only when needed.

This one was tricky:

lazy_test2 <- function(x)
{
    cat("it's... ")
    y <- x+x  # using x twice
    cat(" a man with two noses")
    y
}

lazy_test2({cat("and now for something completely different!"); 7})
## it's... and now for something completely different! a man with two noses
## [1] 14

9.0.18 Ellipsis ...

Represent a variable (non defined) number of parameters.

Function with ... are called variadic function (their parameters vary).

Uses cases:

  • combine an arbitrary number of objects, ex: c()

  • pass further arguments (as-is ?), ex: lapply()

9.0.18.1 Exercise 9.28

lapply(c(3, 9, 7), FUN = runif, min = -1, max = 1)
## [[1]]
## [1]  0.2701484  0.8900861 -0.3277832
## 
## [[2]]
## [1]  0.2863840 -0.4339343 -0.6875908  0.4593573  0.7556213 -0.9246378 -0.4152692
## [8]  0.0729128 -0.1037209
## 
## [[3]]
## [1]  0.85433621  0.13736731  0.33144656 -0.29726829 -0.26489899 -0.61349427
## [7] -0.00740801

9.0.18.2 Metaprogramming

1- Using expressions passed as a function w/o evaluating them:

test_deparse_substitute <- function(x)
    deparse(substitute(x))  # does not evaluate whatever is behind `x`

test_deparse_substitute(testing+1+2+3)
## [1] "testing + 1 + 2 + 3"
plot.default((1:100)^2)

9.0.18.3 Exercice 9.30

# [...] From plot.default
    xlabel <- if (!missing(x)) 
        deparse1(substitute(x))
    ylabel <- if (!missing(y)) 
        deparse1(substitute(y))
# [...]

# data:  log(rlnorm(100))

Author is not fan of them (see later!)