Skip to Tutorial Content
## Warning in file(filename, "r", encoding = encoding): URL
## 'https://metrics.rstudioprimers.com/learnr/installClient': status was 'Couldn't
## resolve host name'

[1] “Warning: An error occurred with the client code.”

Functions

Functions are the verbs of R. When you do something in R, you do it by running a function. For example,

  • To take a log, you run a function named log: log(2.71).
  • To fit a linear model, you run a function named lm: lm(mpg ~ wt, data = mtcars).
  • To add two numbers, you run a function named “+”: 1 + 2.

This last one is an alternative way to call the function '+'(1, 2). In R, even things that do not look like functions are functions.

But what is a function?

A function is simply a piece of code that is packaged in a way that makes it easy to reuse.

This short tutorial will show you how R functions are packaged and how you can work with R functions. It is a pre-requisite for the next tutorial, which will show you how to write your own R functions. Let’s begin!

Parts of a function

Every R function has three parts:

  1. A body of code
  2. A set of formal arguments
  3. An environment (where the function will look up the values of the objects within it)

You can inspect each part of a function with three helper functions:

  1. body()
  2. formals()
  3. environment()

Let’s use these helpers to see how the xor function works. xor is a logical operator that returns TRUE if one, but not both, or its arguments evaluates to TRUE.

body()

  • Run body(xor) to see the code body of xor. Then click Submit Code.
body(xor)

xor contains one line of code in its body (you can ignore the braces). This isn’t always the case. A function can have as many lines of code as it needs in its body. For example, as.list.data.frame has three lines (most R functions have much more).

body(as.list.data.frame)
## {
##     x <- unclass(x)
##     attr(x, "row.names") <- NULL
##     x
## }

When a function contains more than one line of code in its body, R will run the entire body and return the result of the last line.

R will run the code in a function’s code body each time you call the function; but as you can see with xor, the code in a function’s body may not be self-contained.

xor
## function (x, y) 
## {
##     (x | y) & !(x & y)
## }
## <bytecode: 0x5580291a2050>
## <environment: namespace:base>

What is x? What is y? Click Continue to find out.

formals()

Often times, a function will need one or more named values to do its job. These values are the formal arguments of the function. The formal arguments of xor are x and y.

formals() returns a list of the formal arguments of a function. If an argument in the list does not come with a value, you will need to supply a value when you call the function. If a function does not have any formal arguments (always possible), formals() will return NULL.

  • Use formals() to see the formal arguments of xor (hint: they are x and y). Then click Submit Answer.
formals(xor)

environment()

Each function is associated with an R environment. The association tells R how to look up any objects that are used by a function, but not defined in its arguments. We’ll learn more about environments later, so you do not need to worry about them now. However, looking up a function’s environment is a handy way to tell which package the function comes in.

  • Use environment() to see the environment associated with the gather function.
environment(gather)

names

You can look up all three parts of a function at once by typing the name of the object that the function is stored in. This is what you think of as the “name of the function.” (In reality, functions do not have names, but they are stored in objects that have names.)

For example, the xor function is a nameless function stored in the object named xor. To see the function in full, type xor.

xor
## function (x, y) 
## {
##     (x | y) & !(x & y)
## }
## <bytecode: 0x5580291a2050>
## <environment: namespace:base>

Help pages

And never forget: you can learn more about any R function by looking up its help page. To do this, type the “function’s name” preceded by a question mark, e.g.

?xor

When you type this into an R IDE, a help page will open in a separate tab.

Quiz

Primitives

You should also know about an important class of R functions called primitives. Most R functions call other R functions in their code body, but primitives do not. Instead primitives call internally implemented algorithms that are written in a lower level programming language (i.e. a more primitive programming language) like C, C++, or FORTRAN.

R’s primitive functions are designed to be very fast, but you won’t be able to inspect their components. See what happens if you inspect the contents of log, which is a primitive function.

body(log)
## NULL
formals(log)
## NULL
environment(log)
## NULL

That’s enough minutiae! Now, how do you run a function?

Calling functions

To call an R function, type its name followed immediately by an open parenthesis and eventually by a closed parenthesis. The parentheses act as a “trigger” that causes R to run the code in the function’s code body. Note the difference:

Sys.Date
## function () 
## as.Date(as.POSIXlt(Sys.time()))
## <bytecode: 0x558028947468>
## <environment: namespace:base>
Sys.Date()
## [1] "2024-11-28"

If you ever try to run a function and nothing happens, double check to see if you included the closing parenthesis.

If a function requires you to provide values for formal arguments, provide the values between the parentheses.

xor(x = TRUE, y = FALSE)
## [1] TRUE

The best practice is to explicitly write out each argument name followed by an equals sign and then a value. If you leave out the argument names, R will match your values to arguments in the order that they are listed. It is common practice among R users to skip the first one or two argument names and then write out the rest.

Default values

Some R functions will provide a default value for one or more of arguments. In this case, you do not need to pass a value to the argument when you call the function. If you do not provide a value, the function will use the default value.

You will know that an argument comes with a default value, if the argument appears with a value in the formals() list.

  • rnorm generates n random values from a normal distribution. When you call rnorm you can supply the mean and standard deviation of the distribution to draw the values from. Check to see if rnorm uses any default values. For which arguments? What are the values? Click Submit Answer to see if you are right.
formals(rnorm)

You can also spot a function’s default values by examining the function itself. Do you see them?

rnorm
## function (n, mean = 0, sd = 1) 
## .Call(C_rnorm, n, mean, sd)
## <bytecode: 0x558029138c48>
## <environment: namespace:stats>

There is one last thing you should know about functions: functions are like Las Vegas:

What happens in a function stays in the function.

For example, suppose I’ve saved values as x and y.

x <- 1
y <- FALSE

Calling xor will not change those values, even though I’m defining new values for x and y in the function.

xor(x = TRUE, y = TRUE)
## [1] FALSE
x
## [1] 1
y
## [1] FALSE

Moreover, xor won’t remember which values I’ve used in the past. If I forget to define x and y the next time I call xor, xor will return an error. xor won’t even be able to look up the values that I assigned to x and y outside of the function.

xor()
## Error in xor(): argument "x" is missing, with no default

What happens in a function stays in the function.

So don’t worry about using functions. (Ahem, technically you could write a function that would change things outside of the function, but that would be a bad idea, and you would have to try to do it on purpose, and it would be rather hard at that. So don’t worry.)

Quiz

Exercise 1

Exercise 2

  • Find the code body of foo
body(foo)

Exercise 3

Recall the code in foo:

body(foo)
## {
##     a <- 10
##     a
## }

What will be the final value of a if I run the following three lines of code in order?

a <- 1
foo()
a

Congratulations!

You have finished the tutorial.

Function Basics