R Style Guide
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.
<- Sys.getenv("ALLOW_EXPORTS") 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:
<- function(x, cond = FALSE) {
some_func 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
<- function(dat) {
clean_some_data |>
dat ::mutate.(var = sum(x)) # mutate.() is known to be from tidytable
tidytable
}
# Bad
<- function(dat) {
clean_some_data |>
dat mutate.(var = sum(x)) # mutate.() could be from anywhere!
}