Skip to content

Roxygen R6 Guide

Lennart Schneider edited this page May 25, 2020 · 4 revisions

This guide shows how to document R6 objects using roxygen2. In case of differences within different packages regarding style, always stick with the style of the mlr3 core package.

The following examples use the Param class of the paradox package.

Top-Level

Start with the @title, followed by the @description (note that @usage and @format tags are not needed):

#' @title Param Object
#'
#' @description
#' Abstract base class for parameters.

After the @description you should put the S3 methods section, and the @include, @family, @export and @example parts (if applicable).

All other parts of the documentation (i.e., Construction, Fields, Active Bindings, Methods) will be moved directly above the matching R code as done in the following sections.

Construction

Note that each parameter (@param) must be specified via its <name> (e.g., special_vals) followed by its (<type>) in parentheses (e.g., (`list()`), or ([Param])). Then break the line using \cr followed by two spaces indentation and the description of this parameter (e.g., Arbitrary special values this parameter is allowed to take, to make it...):

Param = R6Class("Param",
  public = list(

    ...

    #' @description
    #' Creates a new instance of this [R6][R6::R6Class] class.
    #'
    #' Note that this object is typically constructed via derived classes,
    #' e.g., [ParamDbl].
    #'
    #' @param id (`character(1)`)\cr
    #'   Identifier of the object.
    #' @param special_vals (`list()`)\cr
    #'   Arbitrary special values this parameter is allowed to take, to make it
    #'   feasible. This allows extending the domain of the parameter. Note that
    #'   these values are only used in feasibility checks, neither in generating
    #'   designs nor sampling.
    #' @param default (`any`)\cr
    #'   Default value. Can be from the domain of the parameter or an element of
    #'   `special_vals`. Has value [NO_DEF] if no default exists. `NULL` can be a
    #'   valid default.
    #' @param tags (`character()`)\cr
    #'   Arbitrary tags to group and subset parameters. Some tags serve a special
    #'   purpose:\cr
    #'   * `"required"` implies that the parameters has to be given when setting
    #'     `values` in [ParamSet].
    initialize = function(id, special_vals, default, tags) {
      ...
    },

    ...
 ),

 ...

Fields and Active Bindings

Fields and Active Bindings are documented directly above the matching R code resulting in them being differentiated automatically.

You may stumble across the case that you have to document a Field that was set during construction and the documentation of this Field would be identical to documentation of the parameter of the construction. To prevent too much redundancy here, keep the description of such Fields short (and document everything important within the documentation of the parameter of the construction). Each Field must again be specified via its <name> (e.g., special_vals) followed by the (<type>) in parentheses (e.g., (`list()`)). Then break the line using \cr followed by a description (no indentation here) of this Field (e.g., Arbitrary special values this parameter is allowed to take.):

Param = R6Class("Param",
  public = list(
    #' @field id (`character(1)`)\cr
    #' Identifier of the object.
    id = NULL,
  
    #' @field special_vals (`list()`)\cr
    #' Arbitrary special values this parameter is allowed to take.
    special_vals = NULL,
  
    #' @field default (`any`)\cr
    #' Default value.
    default = NULL,
  
    #' @field tags (`character()`)\cr
    #' Arbitrary tags to group and subset parameters.
    tags = NULL,
  
    ...
  ),

  ...

The same documentation style holds for Active Bindings:

  ...

  active = list(
    #' @field class (`character(1)`)\cr
    #' R6 class name. Read-only.
    class = function() class(self)[[1L]],
  
    #' @field is_number (`logical(1)`)\cr
    #' `TRUE` if the parameter is of type `"dbl"` or `"int"`.
    is_number = function() self$class %in% c("ParamDbl", "ParamInt"),
  
    #' @field is_categ (`logical(1)`)\cr
    #' `TRUE` if the parameter is of type `"fct"` or `"lgl"`.
    is_categ = function() self$class %in% c("ParamFct", "ParamLgl"),
  
    #' @field has_default (`logical(1)`)\cr
    #' Is there a default value?
    has_default = function() !is_nodefault(self$default),
  
    #' @field storage_type (`character(1)`)\cr
    #' Data type when values of this parameter are stored in a data table or sampled.
    ...
  ),

  ...

Methods

Methods need to document all their parameters (same style as for the construction, @param <name> (<type>)) and their return value (@return <return_value>), e.g., for the Param's rep method:

Param = R6Class("Param",
  public = list(
  
    ...
    
    #' @description
    #' Repeats this parameter n-times (by cloning).
    #' Each parameter is named "\[id\]_rep_\[k\]" and gets the additional tag "\[id\]_rep".
    #'
    #' @param n (`integer(1)`).
    #' @return [ParamSet].
    rep = function(n) {
      ...
    }
    
    ...
  ),

  ...

Some Remarks

  • Private Fields and Methods cannot be documented with roxygen2 but it is good practice to follow the same style for internal documentation.

  • If you find yourself reusing the same documentation parts a lot (e.g., for the id), use roxygen2 templates that go into the man-roxygen directory of the package (make sure to ignore this directory when building the package, i.e., via .Rbuildignore). Templates can be directly included in the documentation via @template <name_of_template> (see e.g. the templates of the paradox package for some reference).

  • Make sure that @param and @field sections (and of course all other sections, but there it is more obvious) end with a punctuation mark.

  • When documenting types, make sure that they are put in between two grave accents (`), e.g., (`numeric(1)`). This does not apply to objects that are part of packages, e.g., ([Param]), which are instead put in between two square brackets.

  • Don't forget to include the following line in the DESCRIPTION of the package: Roxygen: list(markdown = TRUE, r6 = TRUE).