```
<- function(n) {
mySqrt return(n^0.5)
}
```

# 5 Creating Functions

## Learning Objectives

- Know the basic syntax of custom functions in R.
- Understand how function arguments work in R.
- Understand the different types of return statements in R.
- Create your own custom functions.
- Understand the concept of helper functions.
- Understand the distinction between local and global variables.
## Suggested Readings

- Chapter 19 of “R for Data Science”, by Garrett Grolemund and Hadley Wickham
- Chapters 2.4 - 2.7 of “Hands-On Programming with R”, by Garrett Grolemund

We already know how to use built-in functions like `sum()`

, `round()`

, `sqrt()`

, etc. And we can access other functions by installing external packages. But many times there just isn’t a function out there to do what you need. Fortunately, you can write your own!

## 5.1 Basic syntax

Here’s the syntax that you use to create a function:

```
FNAME <- function(ARG1, ARG2, ETC) {
STATEMENT1
STATEMENT2
return(VALUE)
}
```

What this does is create a function with the name `FNAME`

, which has arguments `ARG1`

, `ARG2`

, etc. Whenever the function is called, R executes the statements within the curly braces `{}`

, and then returns the `VALUE`

inside the `return()`

statement.

There’s a lot of different pieces to making a function. The way I like to remember how they all go together is to read the following English sentence:

“function name” is a function of () that does…

Each piece of the above sentence corresponds with a piece of code for writing a function:

“function name” | is a | function | of () | that does… |
---|---|---|---|---|

`FNAME` |
`<-` |
`function` |
`(ARG1, ARG2, ETC)` |
`{}` |

All the commands your function will execute go in the `{}`

.

For example, here’s the function `mySqrt(n)`

, which returns the square root of `n`

:

“function name” | is a | function | of () | that does… |
---|---|---|---|---|

`mySqrt` |
`<-` |
`function` |
`(n)` |
`{ return(n^0.5) }` |

And here’s `mySqrt(n)`

written in the typical format:

## 5.2 Arguments

Here’s a function with one argument:

```
<- function(x) {
square <- x^2
y return(y)
}
```

`square(2)`

`#> [1] 4`

`square(8)`

`#> [1] 64`

Here’s a function with multiple arguments:

```
<- function(x, y) {
sumTwoValues <- x + y
value return(value)
}
```

`sumTwoValues(2, 3)`

`#> [1] 5`

`sumTwoValues(3, 4)`

`#> [1] 7`

Functions don’t always have to take arguments. For example:

```
<- function() {
doSomething cat("Carpe diem!") # The cat() function prints whatever's inside it to the console
}
```

`doSomething()`

`#> Carpe diem!`

**Default arguments**:

Sometimes, a function has a parameter that has a natural default. We can specify that default value in the function definition, then choose whether or not to include it in the function call:

```
<- function(x, y=10) {
f return(x + y)
}
```

`f(5) # 15`

`#> [1] 15`

`f(5, 1) # 6`

`#> [1] 6`

## 5.3 The `return()`

statement

Here’s a basic example of using `return()`

to return a value:

```
<- function(x) {
isPositive return (x > 0)
}
```

`isPositive(5) # TRUE`

`#> [1] TRUE`

`isPositive(-5) # FALSE`

`#> [1] FALSE`

`isPositive(0) # FALSE`

`#> [1] FALSE`

The `return()`

statement ends the function immediately:

```
<- function(x) {
isPositive cat("Hello!") # Runs
return(x > 0)
cat("Goodbye!") # Does not run ("dead code")
}
```

`<- isPositive(5) # Prints Hello, then assigns TRUE to x x `

`#> Hello!`

` x`

`#> [1] TRUE`

Notice that in the above example, the `cat("Goodbye!")`

statement is ignored.

If you don’t include a `return()`

statement, R will return the value of the last statement by default (**Don’t do this**):

```
<- function(x) {
f + 42
x }
```

`f(5)`

`#> [1] 47`

```
<- function(x) {
f + 42
x + 7
x }
```

`f(5)`

`#> [1] 12`

## 5.4 The `cat()`

statement

The `cat()`

(short for “concatenating”) statement prints whatever arguments it is given to the console. The arguments can be of mixed types and it will convert them all to a concatenated string:

```
<- function(x) {
printX cat("The value of x provided is", x)
}
```

`printX(7)`

`#> The value of x provided is 7`

`printX(42)`

`#> The value of x provided is 42`

Mixing up `return()`

and `cat()`

is a common early mistake. For example:

```
<- function(x) {
cubed cat(x^3)
}
```

`cubed(2) # Seems to work`

`#> 8`

`2*cubed(2) # Expected 16...didn't work`

`#> 8`

`#> numeric(0)`

Here’s a correct version:

```
<- function(x) {
cubed return(x^3) # That's better!
}
```

`cubed(2) # Works!`

`#> [1] 8`

`2*cubed(2) # Works!`

`#> [1] 16`

## 5.5 Helper functions

It is often useful to break down more complicated problems into smaller “helper functions”. These helpers can be called in other functions. Here’s an example of using the helper functions `square()`

and `squareRoot()`

to compute the hypotenuse of a triangle:

```
<- function(x) {
square return(x^2)
}
<- function(x) {
squareRoot return(x^0.5)
}
<- function(a, b) {
hypotenuse return(squareRoot(square(a) + square(b)))
}
= 3
a = 4
b hypotenuse(a, b)
```

`#> [1] 5`

## 5.6 Local vs. global variables

All variables **inside** a function are called *“local”* variables and will **NOT** be created in the working environment. They can only be used locally within the function. For example:

```
<- function(x, y) {
minSquared = min(x, y)
smaller return(smaller^2)
}
```

`minSquared(3, 4)`

`#> [1] 9`

`minSquared(4, 3)`

`#> [1] 9`

If you try to call a local variable in the global environment, you’ll get an error:

```
<- function(x) {
square <- x^2
y return(y)
} y
```

`#> Error in eval(expr, envir, enclos): object 'y' not found`

*“Global”* variables are those in the global environment. These will show up in the “Environment” pane in RStudio. You can call these inside functions, but this is **BAD** practice. Here’s an example (**Don’t do this!**):

```
<- function() {
printN cat(n) # n is not local -- so it is global (bad idea!!!)
}printN() # Nothing happens because n isn't defined
```

```
= 5 # Define n in the global environment
n printN()
```

`#> 5`

## 5.7 Tips

One particularly useful function is `almostEqual()`

:

```
<- function(d1, d2) {
almostEqual = 0.00001
epsilon return(abs(d1-d2) <= epsilon)
}
```

This is useful when comparing numbers that are stored as floats and have lots of trailing zeros. For example, let’s do some simple addition:

```
<- 0.1 + 0.2
x x
```

`#> [1] 0.3`

If we compared `x`

to `0.3`

, we would expect the result to be `TRUE`

, right?

`== 0.3 x `

`#> [1] FALSE`

What went wrong here? Well, what looks like a value of 0.3 is actually a float with a lot of zeros:

`print(x, digits = 20)`

`#> [1] 0.30000000000000004441`

By default, R doesn’t print out all these zeros, but they are the result of many small rounding errors that occur when computers do calculations.

This is where `almostEqual()`

comes in handy:

`almostEqual(x, 0.3)`

`#> [1] TRUE`

It only compares numbers out to a predefined decimal place, after which it ignores everything else. This will come in handy in your homework problems where you might get unexpected results.

## Page sources

Some content on this page has been modified from other courses, including:

- CMU 15-112: Fundamentals of Programming, by David Kosbie & Kelly Rivers
- Danielle Navarro’s website “R for Psychological Science”