## Learning Objectives

• Define a function that takes arguments.
• Return a value from a function.
• Test a function.
• Explain what a call stack is, and trace changes to the call stack as functions are called.
• Set default values for function arguments.
• Explain why we should divide programs into small, single-purpose functions.

If we only had one data set to analyze, it would probably be faster to load the file into a spreadsheet and use that to plot some simple statistics. But we have twelve files to check, and may have more in the future. In this lesson, weâ€™ll learn how to write a function so that we can repeat several operations with a single command.

### Defining a Function

Letâ€™s start by defining a function `convert_fahr_to_kelvin` that converts temperatures from Fahrenheit to Kelvin:

``````convert_fahr_to_kelvin <- function(temp) {
kelvin <- ((temp - 32) * (5 / 9)) + 273.15
return(kelvin)
}``````

We define `convert_fahr_to_kelvin` by assigning it to the output of `function`. The list of argument names are containted within parentheses. Next, the body of the functionâ€“the statements that are executed when it runsâ€“is contained within curly braces (`{}`). The statements in the body are indented by two spaces, which makes the code easier to read but does not affect how the code operates.

When we call the function, the values we pass to it are assigned to those variables so that we can use them inside the function. Inside the function, we use a return statement to send a result back to whoever asked for it.

## Tip

In R, it is not necessary to include the return statement. R automatically returns whichever variable is on the last line of the body of the function. Since we are just learning, we will explicitly define the return statement.

Letâ€™s try running our function. Calling our own function is no different from calling any other function:

``````# freezing point of water
convert_fahr_to_kelvin(32)``````
``## [1] 273.15``
``````# boiling point of water
convert_fahr_to_kelvin(212)``````
``## [1] 373.15``

Weâ€™ve successfully called the function that we defined, and we have access to the value that we returned.

### Composing Functions

Now that weâ€™ve seen how to turn Fahrenheit into Kelvin, itâ€™s easy to turn Kelvin into Celsius:

``````convert_kelvin_to_celsius <- function(temp) {
celsius <- temp - 273.15
return(celsius)
}

#absolute zero in Celsius
convert_kelvin_to_celsius(0)``````
``## [1] -273.15``

What about converting Fahrenheit to Celsius? We could write out the formula, but we donâ€™t need to. Instead, we can compose the two functions we have already created:

``````fahr_to_celsius <- function(temp) {
temp_k <- convert_fahr_to_kelvin(temp)
result <- convert_kelvin_to_celsius(temp_k)
return(result)
}

# freezing point of water in Celsius
x <- fahr_to_celsius(32.0)``````

This is our first taste of how larger programs are built: we define basic operations, then combine them in ever-large chunks to get the effect we want. Real-life functions will usually be larger than the ones shown hereâ€“typically half a dozen to a few dozen linesâ€“but they shouldnâ€™t ever be much longer than that, or the next person who reads it wonâ€™t be able to understand whatâ€™s going on.

## Challenge - Create a function

• In the last lesson, we learned to concatenate elements into a vector using the `c` function, e.g. `x <- c("A", "B", "C")` creates a vector `x` with three elements. Furthermore, we can extend that vector again using `c`, e.g. `y <- c(x, "D")` creates a vector `y` with four elements. Write a function called `fence` that takes two vectors as arguments, called `original` and `wrapper`, and returns a new vector that has the wrapper vector at the beginning and end of the original:
``````best_practice <- c("Write", "programs", "for", "people", "not",
"computers")
asterisk <- "***"

# R interprets a variable with a
# single value as a vector  with one element.  fence(best_practice,
# asterisk) ``````
• If the variable `v` refers to a vector, then `v[1]` is the vectorâ€™s first element and `v[length(v)]` is its last (the function `length` returns the number of elements in a vector). Write a function called `outside` that returns a vector made up of just the first and last elements of its input:
``````dry_principle <- c("Don't", "repeat", "yourself", "or", "others")
outside(dry_principle)``````
``## [1] "Don't"  "others"``

### The Call Stack

Letâ€™s take a closer look at what happens when we call `fahr_to_celsius(32)`. To make things clearer, weâ€™ll start by putting the initial value 32 in a variable and store the final result in one as well:

``````original <- 32
final <- fahr_to_celsius(original)``````

The diagram below shows what memory looks like after the first line has been executed:

When we call `fahr_to_celsius`, R doesnâ€™t create the variable `temp` right away. Instead, it creates something called a stack frame to keep track of the variables defined by `convert_fahr_to_kelvin`. Initially, this stack frame only holds the value of `temp`:

When we call `convert_fahr_to_kelvin` inside `fahr_to_celsius`, R creates another stack frame to hold `convert_fahr_to_kelvin`â€™s variables:

It does this because there are now two variables in play called `temp`: the argument to `fahr_to_celsius`, and the argument to `convert_fahr_to_kelvin`. Having two variables with the same name in the same part of the program would be ambiguous, so R (and every other modern programming language) creates a new stack frame for each function call to keep that functionâ€™s variables separate from those defined by other functions.

When the call to `convert_fahr_to_kelvin` returns a value, R throws away `convert_fahr_to_kelvin`â€™s stack frame and creates a new variable in the stack frame for `fahr_to_celsius` to hold the temperature in Kelvin:

It then calls `convert_kelvin_to_celsius`, which means it creates a stack frame to hold that functionâ€™s variables:

Once again, R throws away that stack frame when `convert_kelvin_to_celsius` is done and creates the variable `result` in the stack frame for `convert_fahr_to_celsius`: