R Style Guide

guide
r

We use the Tidyverse Style Guide as a base for our style guide. Any deviations or elaborations are described here.

As recommended in the Tidyverse Style Guide, you are encouraged to use {styler} to autoformat your code. {lintr}, which comes with our Visual Studio Code profile, checks your syntax as you type and provides hints to ensure your code adheres to the style guide.

Syntax

Object names

Adhere to snake_case names for variables. Use concise yet informative names – this can be difficult! While dots are common in base R names (see is.na()), please refrain from using dot.case since dots do have syntactic meaning by defining S3 generic methods.

# Good
family_name
worker

# Bad
fileName
long.variable.with.dots

# Chaos
Mixed_Case_With_Underscores
ABSOLUTELY.NOT

For global constants or variables referring to environment variables, use UPPER_CASE_SNAKE_CASE. This is to signify that these variables are not to be modified at runtime. You can create “locked bindings”, but this naming style immediately conveys the intention.

ALLOW_EXPORTS <- Sys.getenv("ALLOW_EXPORTS")

Control flow

If statements

When checking the truthiness of a variable in the if condition, be sure to wrap it in isTRUE() – especially if the variable is provided by the user. For example:

some_func <- function(x, cond = FALSE) {
  if (isTRUE(cond)) {
    # ... Do something ...
  }
}

some_func(1:5, cond = NULL)

If isTRUE() were omitted in favor of if (cond) {...}, then this would cause an error since NULL is technically a length-0 object in R. The condition to if must be length-1; isTRUE() ensures that requirement.

Pipes

In general, prefer the base R pipe introduced in R 4.0: |>. If you use the “Fira Code” typeface, you can take advantage of its font ligatures that visually combine the individual | and > symbols into a right arrow.

Functions

Dependencies on other packages

Use the package::func() qualified call styling for referring to functions from other packages, unless it is cumbersome to do so (e.g. the pipe %>% from magrittr would have to be referred to as magrittr::`%>%`(), which defeats the purpose of using the pipe). This makes it easier for long-term maintenance since the package dependency is explicitly stated.

# Good
clean_some_data <- function(dat) {
  dat |> 
    tidytable::mutate.(var = sum(x)) # mutate.() is known to be from tidytable
}

# Bad
clean_some_data <- function(dat) {
  dat |> 
    mutate.(var = sum(x)) # mutate.() could be from anywhere!
}

See also