Menu

Functions in R: Definition, Arguments and Return Values

How to create a function in R - the function(x) { } syntax, return values, default and named arguments, ... dots, anonymous functions, and how scoping works.

This page includes runnable editors - edit, run, and see output instantly.

Defining and Calling a Function

A function in R is a value, like a number or a string. You build one with the function keyword and pin it to a name with <-, the same way you'd store anything else in a variable:

The parts: function(x) declares one parameter named x, the braces hold the body, and calling square(4) runs the body with x set to 4. For a one-line body the braces are optional - square <- function(x) x^2 is the same function - but braces read better once the body grows.

Because a function is just a value, everything you know about variables applies: you can reassign it, pass it to another function, or store it in a list. That one fact powers half of idiomatic R, including the whole apply family.

Return Values: The Last Expression Wins

An R function returns whatever its last evaluated expression produces. There is no mandatory return statement:

return() does exist, and it works the way you'd expect - it stops the function immediately and hands back its argument. Idiomatic R saves it for early exits: bailing out at the top when an input makes the rest of the work pointless. Pair it with if-else checks:

Writing return(a / b) on the last line wouldn't be wrong, just noise. Reserve return() for the exits that happen early, and let the last expression speak for the normal path.

Default Values and Named Arguments

A parameter can carry a default value, declared with = in the parameter list. Callers who are happy with the default simply omit the argument:

The third call shows the other half of the story: named arguments. When you write name = "Ada" at the call site, position stops mattering - R matches by name first, then fills the remaining parameters by position. Two practical rules fall out of this:

  • Put required parameters first and defaulted ones after them, so positional calls stay natural.
  • At the call site, name any argument that isn't obvious from position. greet("Ada", punctuation = "?") is clearer than making a reader count commas.

Passing Arguments Through with ...

The special parameter ... (pronounced "dots") means "any number of extra arguments." A function that declares ... can accept arguments it never listed and forward them to another function:

shout() doesn't know or care how many words you pass - it hands them all to paste(). Notice that punctuation comes after the dots: any parameter declared after ... can only be set by name, which is exactly what you want for options. This pass-through pattern is everywhere in base R - sapply(x, round, digits = 2) works because sapply forwards digits = 2 to round via its own ....

The cost of dots is that typos slip through silently: misspell punctuation as punctation and it just gets swallowed into ... instead of raising an error. Keep dot-using functions small.

Anonymous Functions

When a function is only needed once - typically as an argument to another function - you can skip the name entirely:

Both lines do the same thing. function(x) x^2 is the classic spelling; \(x) x^2 is the shorthand added in R 4.1, where \ stands in for the word function. They are identical in every way except keystrokes - the shorthand is not a different kind of function.

Use an anonymous function when the operation is a one-liner tied to one call site. The moment you paste the same lambda in two places, or it grows past one line, give it a name - a named function is testable and self-documenting.

Scoping: What a Function Can See

R uses lexical scoping: when a function needs a variable it can't find among its own parameters and local assignments, it looks in the environment where the function was defined - not where it was called. In practice that means a function can read variables from the script around it:

The flip side: assignment inside a function never leaks out. rate <- 0.5 inside change_inside creates a fresh local variable that dies when the function returns; the outer rate still prints 0.1. This is a feature - functions can't accidentally trample your workspace - but it surprises beginners who expect the inner assignment to stick. If a function needs to hand a result to the outside world, return it and assign at the call site. (There is a <<- operator that reaches outward; treat it as a code smell until you genuinely need it.)

A Worked Example

Here's the payoff pattern: notice yourself repeating three lines of analysis, wrap them in a function, reuse it. Say you keep summarizing vectors of measurements:

Everything from this page is in there: a defaulted digits parameter, a named call overriding it, and a last expression (round(out, digits)) doing the returning. The function reads like a sentence, works on any numeric vector, and lives in one place when you decide to add a median.

What You Take Away

  • name <- function(args) { body } creates a function; the last evaluated expression is its return value.
  • return() is for early exits, not for the normal final line.
  • Defaults are declared with = in the parameter list; named arguments make call sites order-independent and readable.
  • ... accepts and forwards any extra arguments - powerful, but it hides typos.
  • function(x) and \(x) are the same thing; use anonymous functions for one-off one-liners.
  • Functions read variables from where they were defined; assignments inside them stay inside.

Next up: the apply family - the functions that take your functions and run them across whole vectors and lists.

Frequently Asked Questions

How do you create a function in R?

Assign a function object to a name: square <- function(x) { x^2 }. The parameters go in the parentheses, the body goes in the braces, and you call it like square(4). The last evaluated expression is what the function returns.

Do you need return() in R?

No. An R function automatically returns the value of the last expression it evaluates. return() exists, and idiomatic R reserves it for early exits - bailing out at the top of a function when an input is invalid or an edge case is handled.

What is an anonymous function in R?

A function you define without giving it a name, usually passed straight into another function: sapply(x, function(v) v^2). Since R 4.1 there is also the shorthand \(v) v^2, which means exactly the same thing with fewer keystrokes.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED