Code Issues

T/F Instead of TRUE/FALSE

Problem

You are writing the abbreviated forms of TRUE and FALSE, T and F or you are using T or F as names.

Solution

Change the abbreviation to the full words or use a different variable name.

Details

In R, T and F are variables being set to TRUE and FALSE, respectively. However, those variables can be redefined by the user since these are not reserved words as TRUE and FALSE are (see the R Language Definition for more details). This can result in unexpected code behavior as users of your package might have variables named T/F.

Examples

The first example shows that you cannot overwrite TRUE:

TRUE <- "Not TRUE anymore"
Error in TRUE <- "Not TRUE anymore": invalid (do_set) left-hand side to assignment
print(TRUE)
[1] TRUE

This throws an error as TRUE is a reserved word and the value of TRUE does not change.

T (and F) on the other hand can be set to a different value:

T <- "Not TRUE anymore"

print(T)
[1] "Not TRUE anymore"

To avoid any unexpected behaviors and inconsistencies, CRAN reviewers will ask you to write the reserved words, TRUE and FALSE instead of their abbreviated forms. For the same reason, T or F should not be used as variable names in your code, examples, tests or vignettes.


Setting a Specific Seed

Problem

In your functions, you are setting a the random seed to a specific number which cannot be changed.

Solution

Remove the code that sets the seed. If you want to set it specifically in your functions, users should be able to set no seed if they want.

Details

Changing the seed is not necessarily forbidden. However, users should be able to control which seed to use. Therefore, avoid code that changes the seed without user consent (e.g.: set.seed(123)). A good solution for allowing to set a seed is to add an argument seed to your function and set it conditionally.

function(... , seed = NULL){
  if(!is.null(seed)){
    set.seed(seed)
  }
  
  #the rest of your function can be written here.
  
}

This allows users to avoid setting a seed if they change the argument to NULL. Ideally, the argument is already set to NULL per default.

Note

In your examples, vignettes, demos and tests setting a seed is not only allowed but also recommended to ensure reproducible results.


Using print()/cat()

Problem

You are using functions, like print() or cat(), to print unsuppressable output to the console.

Solution

Change print()/cat() to message(), warning(), stop(), or wrap them in if(verbose){}.

Details

Information messages, like loop counts or status updates, can clutter the console. While some users prefer this display, others appreciate less information on their console. The use of printing functions for console output is not forbidden on CRAN. However, this output must be suppressable by users.

Note

Printing in special functions like print, summary, interactive functions or methods for generic functions is accepted.

To allow users to suppress the console output CRAN recommends two different ways:

  • exchanging cat()/print() with other generics
    • message(): for information messages and status updates
    • warning(): for warning, will print a “Warning:” before the output
    • stop(): for error messages, will print an “Error:” before the output and halt the execution

This allows to use functions like suppressMessages() to avoid unwanted output.

  • using an additional function argument
    • create one argument in your function to turn off the console output
    • CRAN suggests using verbose, other names are accepted

This example code shows the use of a verbose argument to allow users to suppress printing

foo <- function(..., verbose = TRUE){
  # your code
  if(verbose){
    print("Whatever you want to say!")
  }
  # your code
}

Functions can print per default, like the example above, as long as the printing can be turned off (here, by setting verbose = FALSE).

Note

print() and cat() are not the only functions which can write output onto the console. The issue described in the recipe, also applies to the use of other printing function like writeLines(). If you are using loggers to document your functions’ process, make sure that users can set their log level such that not messages are displayed.


Change of Options, Graphical Parameters and Working Directory

Problem

You are changing the par(), options() or setwd() in your functions, examples, demos or vignettes without resetting them.

Solution

Reset the changed options, in your functions by using on.exit() or in examples, demos and vignettes with an additional line of code after the example.

Details

Ideally, the user’s options are not changed at all. If they really have to be altered, restoring the previous values of user options is mandatory for CRAN packages. The reason for this rule is this line stated in the CRAN Repository Policy:

The code and examples provided in a package should never do anything which might be regarded as malicious or anti-social.

Resetting options is therefore mainly a Quality-of-Life feature for users of your package.

There are different ways of resetting for functions, and examples, demos or vignettes which are recommended by CRAN.

Changing par(), options() or setwd() all invisibly return the previous values and therefore these can be stored in variables using the assignment operator <- and later be restored by calling the variable name as argument in the respective function.

For functions:

When changing options inside one of your package functions, you can use on.exit() for restoring.

foo <- function(x){
  
  # par():
  oldpar <- par(mfrow = c(2,2))
  on.exit(par(oldpar))
  
  # options():
  oldop <- options(digits = 3)
  on.exit(options(oldop))
  
  # setwd():
  oldwd <- setwd(".")
  on.exit(setwd(oldwd))
  
  # your code which requires a changed option
  
}

This will reset the par(), options() and setwd(). The use of on.exit() makes it possible to restore options before exiting a function even if the function breaks. Therefore it needs to be called immediately after the option change within a function. For more information, call ?on.exit() in your console.

For demos, examples and vignettes: Since no function is exited when changing options in examples, on.exit() cannot be used. CRAN recommends the following way for restoring options:

oldpar <- par(mfrow = c(2,2))

# your code which requires a changed option

par(oldpar)

Here the code will only reset the options if the example runs without breaking. Therefore, try to keep the code between setting and resetting as concise as possible. Restoring the options() and setwd() can be done using the same principle as for par() shown above.

Tip

If you need to change more than one option in the same function, example, vignette or demo, you can use oldpar <- par(no.readonly = TRUE) or oldop <- options() to reset all parameters at once. Saving the entire Note, that for par() the no.readonly argument must be set to TRUE or else warnings will be produced.

Note

The issue described in the recipe, also applies to the use of other function which change some parameters persistently, like Sys.setLanguage.