R uses lexical scoping which means that if an object is referenced but not defined in a function then it is looked for in the environment in which the function is defined, not the environment from which it was called.
z is referenced in g but is not defined in g so it looks to the environment in which g is defined and that is the environment within f so g uses z = 4.
Actually in this case the environment that g is defined in is the same as the environment from which g is called so any way you look at it z = 4 must be used. If functions defaulted to the global environment to look for objects not defined in the function then it would use z = 10 but that is not how R works.
Making it work differently
If for some reason you wanted to force g to look for z in the environment in which f is called then you could do this (where parent.frame()
refers to the environment from which f is called).
f2 <- function(x, envir = parent.frame()) {
g <- function(y) {
y + with(envir, z)
}
z <- 4
x + g(x)
}
z <- 10
f2(3)
## [1] 16
or we could use y + envir$z
except that that would only look in the parent frame and not in its ancestors whereas with
will look in ancestors of the parent frame if not found in the parent frame.
An alternative is to change g's environment like this so that it looks into envir
for objects not found in g:
f3 <- function(x, envir = parent.frame()) {
g <- function(y) {
y + z
}
environment(g) <- envir
z <- 4
x + g(x)
}
z <- 10
f3(3)
## [1] 16
4 + 2*x
in the end? Where 4 = z – Markoz1 <- 4
within function andf(3)# [1] 16
– Cataniaz <- 4; environment(g) <- .GlobalEnv
and then callz <- 10 > f(3) [1] 16
– Catania