I have been reading Hadley Wickham's Advanced R in order to gain a better understanding of the mechanisms of R and how it works behind the scene. I have so far enjoyed it and everything is quite clear. There is one question that occupies my mind for which I have not yet found an explanation. I am quite familiar with the scoping rules of R which determine how values are assigned to FREE VARIABLES. However, I have been grappling with the question of why R cannot find the value of a formal argument through lexical scoping in the first case. Consider the following example:
y <- 4
f1 <- function(x = 2, y) {
x*2 + y
}
f1(x = 3)
It normally throws an error because I didn't assign a default value for argument y
. However, if I create a local variable y
in the body of the function it won't throw any error:
I also read in Professeur Matloff's book that arguments act like local variables, so that's why this question remains a mystery for me.
f1 <- function(x = 2, y) {
y <- 4
x*2 + y
}
f1(x = 3)
And also here there is no error and it is quite clear why:
y <- 2
f2 <- function(x = 2) {
x*2 + y
}
f2()
Thank you very much in advance.
Note that R will only throw the error when you go to use the variable. if you had
f1 <- function(x = 2, y) {
x*2 + 5
}
f1(x = 3)
# [1] 11
everything would be fine. That's because the parameter is a "promise" which isn't resolved till you actually use it. This allows you to do things like
f1 <- function(x = 2, y=x+5) {
x*2 + y
}
f1(x = 3)
# [1] 14
Where the y
value will actually use the value of x
that's passed to the function when the promise is evaluated. Furthermore you can also do
f1 <- function(x = 2, y=z+2) {
z <- x + 10
x*2 + y
}
f1(x = 3)
[1] 21
Where y
is able to take the value of z
that didn't even exist when the function was called. Again this is because the parameter values are promises and are only evaluated when they are actually used. They have access to all the values in the environment when they are evaluated. But note that this only works because default parameter values are evaluated in the context of the function body. This is different than when you pass in a value to a function. In that case the value is evaluated in the calling environment, not the local function body. So you can't do
f1(x = 3, y=z+2)
# Error in f1(x = 3, y = z + 2) : object 'z' not found
The the reason you get the error in your first function is that a value for y
does not exist when you try to use it in x*2 + y
. Since you've defined y
as a parameter, it is no longer a "free" variable and will not be looked up in parent scope. You don't get an error in your second function because you've re-bound the y
variable to a local function variable so you are never using the parameter value at all.
If you ran
f1 <- function(x = 2, y) {
y <- 4
x*2 + y
}
f1(x = 3, y=200)
# [1] 10
The 2000 basically disappears. You no longer have access to that value after you reassign y
. R does not check if a variable exists already before redefining so there is nothing that will try to evaluate the promise value y
of the function parameter.
Arguments will act like local variables once the promise has been evaluated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With