Search code examples
rfunctiondefault-arguments

Function Argument Evaluation in R


I have been reading Hadley Wickham's Advanced R in the past couple of weeks and one particular concept has caught my attention which I would be grateful if you could provide me with an explanation:

The evaluation environment is slightly different for default and user supplied arguments, as default arguments are evaluated inside the function.

and the following example is presented by the book:

h05 <- function(x = ls()) {
a <- 1
x
}
# ls() evaluated inside h05:
h05()
#> [1] "a" "x"
# ls() evaluated in global environment:
h05(ls())
#> [1] "h05"

Here it is quite clear that the when the user provide ls() as a value to argument x it is evaluated in the global environment. However in the following example when we provide 2 values for x and y it does not affect their value in the global environment, despite the fact they are being evaluated there:

y <- 6
x <- 5

f1 <- function(x, y) {
  x*2 + y
}

f1(x = 4, y = 12)

I would like to know what am I missing here and whether the aforementioned rule only holds true when we define and argument in terms of other arguments within a function call.

Any explanation in much appreciated.


Solution

  • After the discussion in comments, here is an answer:

    The lines

    y <- 6
    x <- 5
    

    create two global variables.

    The function definition

    f1 <- function(x, y) {
      x*2 + y
    }
    

    creates a function named f1 that has two arguments named x and y. When you call it, it will create variables x and y which are visible while evaluating the body of f1. Those are called local variables. They will normally disappear when the function is finished. The values of those variables will be the values of the expressions being passed in.

    When you call it as

    f1(x = 4, y = 12)
    

    it evaluates the expressions 4 and 12 in the global environment to find the values for the local variables. The global variables x and y play no part in this.

    If you do a call like

    f1(x = 4, y = y <- x)
    

    it will evaluate 4 as before, but when it evaluates y <- x it will be using the global variables: so that changes the global value y to 5. It also sets the local variable y to 5, because assignments return the value being assigned.

    Edited to add: the discussion above ignores "lazy evaluation", so things don't happen in the order described. In fact, the arguments won't be evaluated until the local variables are used in the expression x*2 + y. This makes no difference in this function, but in more complicated situations order of evaluation sometimes makes a difference.