R Functions

Creating Functions and Understanding Scope in R

Prework

Before starting this module:

  • Review how to assign variables and write simple expressions in R.
  • Think about the functions you’ve used so far (mean(), sd(), boxplot()).
    What do all functions have in common?
  • Open RStudio and create a new script file named functions_practice.R.

Overview

So far, we’ve been using R functions as tools.
Now, you’ll learn how to create your own.

A function in R is a reusable set of instructions that can take inputs (arguments), perform actions, and return outputs (results).
You’ll also learn about scope: the idea of where variables “live” inside or outside functions.

By the end of this module, you’ll be able to:

  • Define and call simple functions in R.
  • Use arguments and return values effectively.
  • Distinguish between printed and returned output.
  • Explain the difference between local and global variables.

Defining a Function

Creating a function is just like creating any other R object: you give it a name and assign it a value. This is also referred to as defining a function. To use this function we call or execute the function by writing its name, followed by parenthesis. ().

# Simplest function
f <- function(){}

f()   # returns NULL because it does nothing
NULL

A function is an object like any other variable in R. Since R is dynamically typed we are free to redefine f:

f <- 10
f    # f is now numeric, not a function
[1] 10

You can redefine it anytime:

f <- function(){}

Adding Behavior

A function performs whatever expressions you include inside {}.

f <- function(){
  "Hello, world!"
}

f()
[1] "Hello, world!"

If no explicit return() is used, the last evaluated expression is returned automatically. Notice that the item returned is printed too unless you assign it to a variable

f <- function(){
  "Hello, world!"
}

val <- f()

or use invisible:

f <- function(){
  invisible("Hello, world!")
}

f()

To stop early or specify what to explicitly return, use return():

f <- function(){
  return("AHHH!")
  "Hello, world!"
}

f()
[1] "AHHH!"

Printing vs. Returning

A function can both print and return values, but they are different.

f <- function(){
  print("AHHH!")     
  print("Hello, world!")  # printed output
}

f()
[1] "AHHH!"
[1] "Hello, world!"

print() sends output to the console.
return() (or the last expression) sends a value back to R for later use.

What’s been returned can be stored in a variable for later use:

f <- function(){
  print("AHHH!")     
  print("Hello, world!")  # printed output
}

val <- f()
[1] "AHHH!"
[1] "Hello, world!"
val
[1] "Hello, world!"

Scope: Where Variables Live

Each function creates its own small environment where variables can exist locally.
Variables defined outside a function are global. In this example, f and a are global.

a <- 1

f <- function(){
  b <- 2
  print(b)
}

f() # f is being called and local variables are created
[1] 2

Here, b exists only while f() runs and it’s local to the function.

Local Parameters

You can also define local variables as parameters:

a <- 1

f <- function(b){
  print(b)
}

f(2)
[1] 2

Inside f(), b is local. It disappears after the function finishes.

Global and Local Together

If a variable isn’t found inside a function, R looks in the global environment:

a <- 1

f <- function(b){
  print(a + b)
}

f(2)
[1] 3

We don’t usually code this way — by accessing variables we expect might live out of the function in the global scope. There is an exception for functions. Because functions are defined globally, this allows us to use them inside other functions.

add_one <- function(a){
  a + 1
}

f <- function(b){
  add_one(b)
}

f(2)
[1] 3

Practice

Answer the following for each example:

  1. What are the local variables?
  2. What are the global variables?
  3. What is the output from the code?

Example 1

a <- 10
f <- function() {
  b <- 2
  print(a + b)
}
f()

Global: a is 10, f is a function Local: b is 2.
Output: 12.

Example 2

a <- 5
f <- function(a) {
  b <- 2
  print(a + b)
}
f(10)

Global: a is 5, f is a function Local: a is 10, b is 2.
Output: 12.

Example 3

a <- 1
f <- function(b) {
  a <- a + b
  print(a)
}
f(3)
print(a)

Global: a is 1, f is a function Local: a is 4, b is 3.
Output: 4 and then 1.

Example 4

f <- function(x) {
  y <- x + 1
  print(y)
  y * 2
}
z <- f(3)
z

Global: f is a function, z is 8. Local: x is 3, y is 4.
Output: 4 and then 8.

Example 5

g <- function(x) {
  y <- x^2
  invisible(y)
}
w <- g(5)

Global: g is a function, w is 25. Local: x is 5, y is 25.
Output: None