SyntaxStudy
Sign Up
R Defining and Calling Functions
R Beginner 1 min read

Defining and Calling Functions

Functions in R are first-class objects created with the function keyword. The basic syntax is function(arg1, arg2, ...) { body }, and the return value is either the value passed to return() or, by R convention, the last evaluated expression in the function body. Because functions are objects, you can assign them to variables, pass them as arguments to other functions, and return them from functions, enabling powerful functional programming patterns. Arguments in R can be matched by position, by name, or partially by name (partial matching is convenient but can be a source of subtle bugs in larger codebases). Default values are specified with = in the argument list and are evaluated lazily — that is, only when the argument is actually needed. The special ... (dot-dot-dot) argument allows a function to accept an arbitrary number of additional arguments and pass them on to another function, which is the basis of the wrapper pattern used throughout R. Function scoping follows lexical (static) rules. A function looks up free variables in the environment in which it was defined, not the environment from which it was called. This means a function defined inside another function captures the enclosing function's variables, enabling closures. Understanding this behaviour is essential for writing correct helper functions and avoiding hard-to-find bugs caused by accidental variable capture.
Example
# Basic function definition
greet <- function(name, greeting = "Hello") {
    paste(greeting, name)
}
greet("Alice")             # "Hello Alice"
greet("Bob", "Hi")         # "Hi Bob"
greet(greeting = "Hey", name = "Carol")  # named args, any order

# Last-expression return (no explicit return() needed)
square <- function(x) x ^ 2
square(7)   # 49

# Explicit return for early exit
safe_log <- function(x) {
    if (x <= 0) return(NA)
    log(x)
}
safe_log(-1)   # NA
safe_log(10)   # 2.302585

# Variadic functions with ...
my_paste <- function(..., sep = " ") {
    args <- list(...)
    paste(args, collapse = sep)
}
my_paste("one", "two", "three", sep = "-")  # "one-two-three"

# Passing ... to another function
loud_mean <- function(x, ...) {
    result <- mean(x, ...)
    cat("Mean is:", result, "\n")
    invisible(result)
}
loud_mean(c(1, 2, NA), na.rm = TRUE)   # Mean is: 1.5

# Closures: function factories
make_power <- function(exp) {
    function(x) x ^ exp    # captures 'exp' from enclosing env
}
square <- make_power(2)
cube   <- make_power(3)
square(4)   # 16
cube(3)     # 27

# Anonymous functions (lambda-style)
(function(x, y) x + y)(5, 3)   # 8
sapply(1:5, function(x) x * x)  # 1 4 9 16 25