If you’ve used R for any length of time, you would have likely come across this statement;
Functions are objects.
I was reading the book Advanced R the other day and Hadley Wickham was saying it again. Then somehow it dawned on me that functions really are objects!
So, what is an object in R? According to the R manual An Introduction to R, which I think no one ever reads, an object is simply an entity upon which R operates. The document went ahead to cite atomic vectors as examples. In code, that’s
# Some atomic vectors x <- 1:8 y <- c("apples", "grow", "on", "trees") z <- runif(10) x y z
##  1 2 3 4 5 6 7 8 ##  "apples" "grow" "on" "trees" ##  0.10622862 0.86598075 0.11847392 0.49576064 0.06002724 0.79476014 ##  0.86503160 0.33285702 0.52400112 0.42741101
Here, the operations underlying
runif are creating objects that have been named
z, respectively. We will (very) colloquially call them constructors—not necessarily in the sense of an object-oriented programming paradigm.
To create (i.e. define) a function in R, we have the
function function (yes, tautology but it’s right). In the same spirit as the foregoing code, it creates or constructs a function object.
add_two <- function(arg) arg + 2
If we check the objects that are now in the workspace with
ls, we notice that our function is also there.
##  "add_two" "x" "y" "z"
What was for me a kind of epiphany was the realization that a function is a data structure with different parts, pretty much like a list.
## $arg ## ## ## [] ## arg + 2
The functions created by
function are also called closures which have 3 major components:
- formals, which is the argument list
- body, which is the R code (or expression(s)) run when the function is called, and
formals(add_two) body(add_two) environment(add_two)
## $arg ## ## ## arg + 2 ## <environment: R_GlobalEnv>
After creating the function we can call it. It is at this stage that all the components kick in:
pairlistof arguments which are key-value pairs with the key being the parameter’s name and the value is the actual argument supplied to it;
- the body contains the expressions that are parsed by R, returning a value or generating a side-effect e.g. writing to a file; and
environmentthat, simply put, is a container for the names bound to the different objects evaluated in the function (this is what mainly determines scope)
So when we call the function with one of the atomic vectors created earlier,
add_two(arg = x)
##  3 4 5 6 7 8 9 10
we can see that
add_two has added 2 to each element of the vector
Is this knowledge really important? For me, understanding that functions are objects just like others made it easier to reason about them when using them for programming. Additionally, when one ventures into functional programming or meta-programming, it makes these more advanced approaches a lot easier to grasp. But that’s a topic for another day.