3 Functions

3.1 Naming

Use verbs for function names, where possible.

# Good
add_row()
permute()

# Bad
row_adder()
permutation()

3.2 Long lines

If a function definition runs over multiple lines, indent the second line to where the definition starts.

# Good
long_function_name <- function(a = "a long argument",
                               b = "another argument",
                               c = "another long argument") {
  # As usual code is indented by two spaces.
}

# Bad
long_function_name <- function(a = "a long argument",
  b = "another argument",
  c = "another long argument") {
  # Here it's hard to spot where the definition end and the
  # code begins
}

3.3 return()

Only use return() for early returns. Otherwise rely on R to return the result of the last evaluted expression.

# Good
find_abs <- function(x, y){
  if (x > 0) return(x)
  x * -1
}
add_two <- function(x, y) {
  x + y
}

# Bad
add_two <- function(x, y) {
  return(x + y)
}

If your function is called primarily for its side-effects (like printing, plotting, or saving to disk), it should return the first argument invisibly. This makes it possible to use the function as part of a pipe. print methods should usually do this, like this example from httr:

print.url <- function(x, ...) {
  cat("Url: ", build_url(x), "\n", sep = "")
  invisible(x)
}

3.4 Comments

In code, use comments to explain the “why” not the “what” or “how”. Each line of a comment should begin with the comment symbol and a single space: #.

3.5 Design

There are two main design principles to bear in mind:

  • A function should do one thing well.

    A function should be called either because it has side-effects or because it returns a value; not both. Strive to keep blocks within a function on one screen, < 30 lines.

  • A function should be easily understandable in isolation.

    Avoid global options. If your function has a transient side-effect (i.e. you need to create a temporary file or set an option), clean up after yourself with on.exit().