Search code examples
rroxygen2

Issue when documenting new "+" S3 method with roxygen2


I am trying to define a new "+" S3 method in my package for a class class1. I use roxygen2 to generate the function man page, and I encounter an issue when documenting the usage of the function, the issue being either a strange "Usage" section in the man page, or warnings when checking the package.

This "+" S3 method can take one or two operands like the standard addition:

#' Add objects of type "class1"
#' @rdname add.class1
#' 
#' @param x an object of class "class1"
#' @param y an object of class "class1"
#'
#' @return an object of class "class1"
#' @export
"+.class1" <- function(x, y = NULL) {
    if(!is.null(y)) {
        return(class1(x$value + y$value))
    } else {
        return(class1(+ x$value))
    }
}

If I don't specify any @usage section in the roxygen2 documentation chunk, when I generate the man page (with devtools::document()) and read the function doc (with ?"+.class1"), I get the following in the "Usage" section of the man page (which is not very clear in my opinion):

## S3 method for class 'class1'
x + y = NULL

If I specify a @usage section in the roxygen2 documentation chunk of the +.class1 method, like this:

#' Add objects of type "class1"
#' @rdname add.class1
#' @usage
#' +x
#' x + y
#'
#' @param x an object of class "class1"
#' @param y an object of class "class1"
#'
#' @return an object of class "class1"
#' @export
"+.class1" <- function(x, y = NULL) {
    if(!is.null(y)) {
        return(class1(x$value + y$value))
    } else {
        return(class1(+ x$value))
    }
}

I get a pretty "Usage" section in the man page:

+x
x + y

But I get a warning when checking the package:

Objects in \usage without \alias in documentation object '+.class1':
  ‘+’

I can add an alias in the roxygen2 documentation chunk with @aliases + like this:

#' Add objects of type "class1"
#' @rdname add.class1
#' @aliases +
#' @usage
#' +x
#' x + y
#'
#' @param x an object of class "class1"
#' @param y an object of class "class1"
#'
#' @return an object of class "class1"
#' @export
"+.class1" <- function(x, y = NULL) {
    if(!is.null(y)) {
        return(class1(x$value + y$value))
    } else {
        return(class1(+ x$value))
    }
}

then the warning is gone, but in practice I am implementing two classes with their own "+" S3 method, then if I have a @usage tag (to get nice man page "Usage" section) and a @aliases + tag (to avoid the warning I just mentioned above) in both class roxygen documentation chunks (c.f. below), I get a new warning:

Rd files with duplicated alias '+':
  ‘add.class1.Rd’ ‘add.class2.Rd’

Definition of class1 and class2 "+" S3 methods:

#' Add objects of type "class1"
#' @rdname add.class1
#' @aliases +
#' @usage
#' +x
#' x + y
#'
#' @param x an object of class "class1"
#' @param y an object of class "class1"
#'
#' @return an object of class "class1"
#' @export
"+.class1" <- function(x, y = NULL) {
    if(!is.null(y)) {
        return(class1(x$value + y$value))
    } else {
        return(class1(+ x$value))
    }
}

#' Add objects of type "class2"
#' @rdname add.class2
#' @aliases +
#' @usage
#' +x
#' x + y
#'
#' @param x an object of class "class2"
#' @param y an object of class "class2"
#'
#' @return an object of class "class2"
#' @export
"+.class2" <- function(x, y = NULL) {
    if(!is.null(y)) {
        return(class2(x$value + y$value))
    } else {
        return(class2(+ x$value))
    }
}

Edit: solution thanks to @user2554330 suggestion:

#' @usage
#' \special{+x}
#' \special{x + y}

Solution

  • The syntax used in the help page for +.Date is

    \special{date + x}
    

    (see https://github.com/wch/r-source/blob/d99a0b4cfe4435b212f0eb689ba0b853310c9695/src/library/base/man/Ops.Date.Rd#L19)

    As far as I can see, the \special{} macro is almost completely undocumented, so you might get some sort of warning for using it.

    The bit64 package uses different syntax:

    \method{+}{integer64}(e1,e2)
    

    which is displayed as

    ## S3 method for class 'integer64'
    e1 + e2
    

    (see https://github.com/truecluster/bit64/blob/e428535bc31982d85bc3f4faa1f2ae8481280781/man/xor.integer64.rd#L35)

    Similarly, the bit package documents unary ! with

    \method{!}{bit}(x)
    

    and it is displayed as !x. This style seems like a better choice than using \special{}.

    Edited to add: I tried \method{+}{bit}(x) and it failed, presumably because + is a binary operator, even though it can be used in a unary way. So maybe you should just skip the unary usage, or use the \special{} macro to document it.