Functions
Reviewed & published by Brayan K
A function is a reusable block of R code that takes inputs (arguments), does some work, and returns a result — letting you name and repeat logic instead of copying it.
Part of the free R course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end of this lesson you'll define your own functions, give arguments default values, return values (automatically or with return()), and understand how local scope keeps functions self-contained.
What You'll Learn in This Lesson
- How to define a function with function(args) { ... }
- How R returns the last expression automatically
- How to use return() for early exits
- How to give arguments default values
- How to pass arguments by position or by name
- How local scope keeps function variables private
1️⃣ Defining a Function
You create a function with the function keyword, list its arguments in parentheses, and put the body in braces. The value of the last expression is returned automatically — no return needed.
# A function packages reusable code. Define one with function(args) { ... }.
greet <- function(name) {
paste("Hello,", name, "!") # the LAST expression is returned automatically
}
greet("Ada") # -> [1] "Hello, Ada !"
# A function with two arguments that does a calculation:
area <- function(width, height) {
width * height
}
area(4, 5) # -> [1] 202️⃣ Defaults, Named Arguments, and return()
Give an argument a default with name = value to make it optional. Callers can pass arguments by position or by name. Use return() to exit early — perfect for guard clauses.
# Default values make arguments optional.
# Arguments can be passed by position OR by name.
power <- function(base, exponent = 2) { # exponent defaults to 2
base ^ exponent
}
power(5) # uses default -> [1] 25
power(5, 3) # by position -> [1] 125
power(exponent = 3, base = 2) # by name (order doesn't matter) -> [1] 8
# return() exits early — handy for guards:
safe_divide <- function(a, b) {
if (b == 0) return("Cannot divide by zero")
a / b
}
safe_divide(10, 0) # -> [1] "Cannot divide by zero"3️⃣ Scope: What Stays Inside
Variables created inside a function are local — they vanish when the function returns and don't pollute your workspace. A function can read outer (global) variables, but to get a value out, you must return it. Functions are also first-class values: you can store them in lists and pass them around.
# Variables created inside a function are LOCAL — they don't leak out.
multiplier <- 10 # global
scale <- function(x) {
result <- x * multiplier # can READ the global multiplier
result # returns the local result
}
scale(5) # -> [1] 50
# 'result' does not exist out here:
exists("result") # -> [1] FALSE
# Functions are values too — you can store and pass them around:
ops <- list(double = function(x) x * 2, square = function(x) x ^ 2)
ops$square(6) # -> [1] 36Your turn. Fill in the ___ blank, run it, and compare with the expected output.
# 🎯 YOUR TURN — replace each ___ then run it.
# 1) Write a function that converts Celsius to Fahrenheit: F = C * 9/5 + 32
to_f <- function(celsius) {
___ * 9/5 + 32 # 👉 replace ___ with celsius
}
# 2) Call it for a few temperatures
cat("0C =", to_f(0), "F\n")
cat("100C =", to_f(100), "F\n")
# ✅ Expected output:
# 0C = 32 F
# 100C = 212 FMini-Challenge: A Grade Function
Write it from the outline, run it, and check it against the example output. This combines arguments, defaults, if/else, and return().
# 🎯 MINI-CHALLENGE: a grade function.
#
# 1. Write grade(score) that returns:
# "A" if score >= 90
# "B" if score >= 80
# "C" if score >= 70
# "F" otherwise
# (hint: use if / else if / else, and return() for each case)
# 2. Give the function a default score of 0.
# 3. Test it with grade(95), grade(82), grade(40).
#
# ✅ Example output:
# [1] "A"
# [1] "B"
# [1] "F"
# your code hereCommon Errors (and the fix)
- Function returns nothing — if your last line is an assignment (x <- 5), nothing is returned. End with the value itself, or use return(x).
- "argument 'x' is missing, with no default" — you called the function without a required argument. Pass it, or give it a default in the definition.
- Forgetting the braces — multi-line bodies need { }. A single expression can skip them: square <- function(x) x ^ 2.
- Expecting an internal variable outside — local variables don't escape. Return the value and assign the result.
Pro Tips
- 💡 One job per function: small functions that do one thing are easier to test and reuse.
- 💡 Name your arguments when calling: it makes complex calls readable and protects against argument-order changes.
- 💡 Return a list for multiple results: list(mean = m, sd = s) hands back several values at once.
📋 Quick Reference — Functions
| Task | R Syntax |
|---|---|
| Define a function | f <- function(x) { x + 1 } |
| Default argument | function(x, n = 2) |
| Early return | return(value) |
| Call by name | f(n = 3, x = 1) |
| One-line body | function(x) x ^ 2 |
| Return many values | list(a = 1, b = 2) |
🎉 Lesson Complete!
- ✅ Define functions with function(args) { ... }
- ✅ R returns the last expression automatically
- ✅ return() exits early for guard clauses
- ✅ Default arguments make inputs optional
- ✅ Local variables stay inside the function
Practice quiz
Which keyword defines a function in R?
- def
- func
- function
- lambda
Answer: function. You create a function with the function keyword: f <- function(x) { ... }.
If you write no return(), what value does an R function return?
- NULL always
- The value of the last expression evaluated
- The first argument
- An error
Answer: The value of the last expression evaluated. R automatically returns the value of the final expression in the body.
What is return() mainly used for?
- To define defaults
- To print output
- To create a loop
- To exit the function early
Answer: To exit the function early. return() lets a function exit early, which is handy for guard clauses.
How do you give an argument a default value?
- function(x, n = 2)
- function(x, n := 2)
- function(x, default n 2)
- function(x, n -> 2)
Answer: function(x, n = 2). Write name = value in the argument list, e.g. function(x, n = 2).
What does power(exponent = 3, base = 2) demonstrate?
- A syntax error
- Passing arguments by name, order-independent
- Returning two values
- Recursion
Answer: Passing arguments by name, order-independent. Named arguments can be given in any order regardless of definition order.
A variable created inside a function with <- is:
- Global to the whole session
- Stored in a file
- Shared across all functions
- Local and gone when the function returns
Answer: Local and gone when the function returns. Local variables live in the function's scope and disappear when it returns.
Can a function READ a global variable it does not define locally?
- Yes, via lexical scoping
- No, never
- Only with <<-
- Only if it is a number
Answer: Yes, via lexical scoping. A function can read outer/global variables; to send a value out, it must return it.
For a one-line body, which definition is valid?
- function x: x ^ 2
- square <- function(x) x ^ 2
- function(x) -> x ^ 2
- def square(x) x ^ 2
Answer: square <- function(x) x ^ 2. A single-expression body can skip the braces: function(x) x ^ 2.
How can a function return SEVERAL values at once?
- By returning a list, e.g. list(mean = m, sd = s)
- It cannot return more than one value
- By printing them
- By using two return() lines
Answer: By returning a list, e.g. list(mean = m, sd = s). Return a list (or vector) to hand back multiple named results.
What does "argument 'x' is missing, with no default" mean?
- x was spelled wrong
- x must be a number
- A required argument x was not supplied and has no default
- The function has too many arguments
Answer: A required argument x was not supplied and has no default. You called the function without a required argument; pass it or give it a default.
Continue this course
- Previous: Factors
- Next: Control Flow — Make decisions and repeat work with if/else, for, and while
- Quick reference: R cheat sheet
Frequently asked questions
How do I return a value from an R function?
R automatically returns the value of the last expression evaluated, so you often don't need return() at all — just put the result on the final line. You can use return() explicitly when you want to exit early, for example inside an if check that handles a special case. Both styles are valid; many R programmers reserve return() for early exits and let the final line be the natural result.
What is the difference between positional and named arguments?
When you call a function, you can supply arguments by position (in the order they're defined) or by name (argument = value). Named arguments are clearer and order-independent, so power(exponent = 3, base = 2) works even though base comes first in the definition. A common style is to pass the first one or two obvious arguments by position and name the rest, especially optional ones, to make your code self-documenting.
What are default argument values for?
A default lets an argument be optional. In function(x, n = 10) the caller can omit n and get 10, or pass their own value to override it. Defaults make functions flexible without forcing every caller to specify everything. Many base R functions use them heavily — for instance round(x, digits = 0) defaults to rounding to whole numbers unless you ask for more digits.
Why can't I see a variable created inside a function?
Variables defined inside a function live in that function's local scope and disappear when the function finishes — this is by design and keeps functions self-contained. A function can read variables from the surrounding (global) environment, but anything it creates internally stays internal. If you need a value outside, return it from the function and assign the result, e.g. out <- myfun(x).