For the second question, the reason you can pass x like a variable rather than a string is due to non-standard evaluation. Effectively, the function arguments are captured rather than being immediately evaluated, and then evaluated within the scope that they exist. For example, with the quote()
function, we can capture the input as-is, rather than looking for the value inside var
. Then, we can evaluate it inside another environment like the mtcars
data frame.
var <- quote(mpg)
> var
mpg
eval(var, envir = mtcars)
[1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
[16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
[31] 15.0 21.4
We can make a similar use of NSE within functions:
f <- function(x) {
input <- substitute(x)
print(input)
eval(input, envir = mtcars)
}
Here, we capture whatever was passed to the argument, and then execute it in the scope of the mtcars
data frame.
f(cyl)
cyl
[1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
You can read more about this at the above link and here.
Using Standard Evaluation
We can achieve the same results without NSE, but the way we call the functions will differ. In this case, arguments will be immediately evaluated and you will get an object not found error if you pass an undefined variable to the function.
f <- function(x) {
print(x)
mtcars[[x]]
}
To use this function, mpg
must be passed as a string.
f("mpg")
[1] "mpg"
[1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
[16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
[31] 15.0 21.4
You can see the results are identical to the first example, but in this case mpg
is a string rather than a captured expression. The second line of the function can be interpreted as mtcars[["mpg"]]
. Trying to use NSE with this function will result in an error:
f(mpg)
Error in print(x) : object 'mpg' not found