56

I've read the Roxygen2 PDF and this site, and I'm lost on the difference between @method @S3method @export and how to use these to properly document S3 methods. I worked up the follow example for discussion:

  1. How would I properly document these?

  2. How do I emulate documentation of ?print and other generic functions that show the use cases for all class-specific implimentations (i.e. the way ?print shows usage for 'factor', 'table','function')

  3. From the wiki page: "All exported methods need the @S3method tag. It has the same format as @method. This exports the method, not the function - i.e. generic(myobject) will work, but generic.mymethod(myobject) will not."
    I can't interpret this. This seems to say that function/method calls won't work properly if the tags are improperly specified? What specifically will break?
    MyHappyFunction = function( x , ... )
    {
        UseMethod( "MyHappyFunction" )
    }
    
    MyHappyFunction.lm = function( x , ... )
    {
      # do some magic
    }
mhovd
  • 3,724
  • 2
  • 21
  • 47
Suraj
  • 35,905
  • 47
  • 139
  • 250

2 Answers2

79

As of roxygen2 >3.0.0, you only need @export:

#' A description of MyHappyFunction
#'
#' A details of MyHappyFunction
#'
#' @title MyHappyFunction: The my happy function
#' @param x numeric number
#' @param ... other arguments
#' @examples
#' a <- 1
#' class(a) <- "lm"
#' MyHappyFunction(a)
#' @export
MyHappyFunction <- function(x, ...){
  UseMethod("MyHappyFunction")
}

#' @rdname MyHappyFunction
#' @export
MyHappyFunction.lm = function(x, ...) {
  # do some magic
}

#' @rdname MyHappyFunction
#' @export
MyHappyFunction.default = function(x, ...) {
  # do some magic
}

But since you're not actually documenting the methods, the following is sufficient:

#' A description of MyHappyFunction
#'
#' A details of MyHappyFunction
#'
#' @title MyHappyFunction: The my happy function
#' @param x numeric number
#' @param ... other arguments
#' @examples
#' a <- 1
#' class(a) <- "lm"
#' MyHappyFunction(a)
#' @export
MyHappyFunction <- function(x, ...){
  UseMethod("MyHappyFunction")
}

#' @export
MyHappyFunction.lm = function(x, ...) {
  # do some magic
}

#' @export
MyHappyFunction.default = function(x, ...) {
  # do some magic
}
hadley
  • 102,019
  • 32
  • 183
  • 245
  • 3
    This example is so simple and clear that it probably belongs here: http://adv-r.had.co.nz/OO-essentials.html#s3 – Brandon Bertelsen May 07 '14 at 00:08
  • 8
    hmm. is there any chance this is broken in latest r-devel? I'm using roxygen2 4.1.1 and development R (rev 68657) and have an example that looks just like this (as far as I can see) where the S3 methods are not getting recognized properly ... – Ben Bolker Jul 20 '15 at 16:53
  • 7
    @BenBolker me too, S3 is being exported() instead of S3'd in namespace packageVersion("roxygen2") # [1] ‘4.1.1’ – tim Aug 21 '15 at 09:10
  • 3
    I had the same problem as BenBolker and tim and found the solution here https://stackoverflow.com/a/29639694/2544467 – Julian Karch Jun 19 '18 at 17:25
42

The @method tag generates \method entries in the \usage field in Rd files.

The @S3method tag generates S3method() entries in the NAMESPACE file.

The @export tag generates export() entries in the NAMESPACE file.

Here is my example:

#' A description of MyHappyFunction
#'
#' A details of MyHappyFunction
#'
#' @title MyHappyFunction: The my happy function
#' @param x numeric number
#' @param ... other arguments
#' @examples
#' a <- 1
#' class(a) <- "lm"
#' MyHappyFunction(a)
#'
#' @rdname MyHappyFunction
#' @export MyHappyFunction
MyHappyFunction <- function(x, ...){
  UseMethod("MyHappyFunction")
}

#' @return \code{NULL}
#'
#' @rdname MyHappyFunction
#' @method MyHappyFunction lm
#' @S3method MyHappyFunction lm
MyHappyFunction.lm = function(x, ...) {
  # do some magic
}

#' @return \code{NULL}
#'
#' @rdname MyHappyFunction
#' @method MyHappyFunction default
#' @S3method MyHappyFunction default
MyHappyFunction.default = function(x, ...) {
  # do some magic
}

enter image description here

3 From the wiki page...

I guess that it means "you do not write @S3method generic mymethod myobject."

Triad sou.
  • 2,969
  • 3
  • 23
  • 27
  • 10
    Correct. But `@method` + `@export` is equivalent to `@s3method` – hadley Aug 26 '11 at 11:46
  • Hadley - two questions 1. When I use just \@S3method I see slightly different documentation than when I use \@method & \@S3method. In the latter case, I get the following in my usage doc "## S3 method for class..." So both tags are required? 2. per my second question above, can you confirm: the only way that the documentation collapses to the generic is if the class-specific implimentations omit all documentation (so no params, no description, etc.)? Or better: what is the requirements to collapse documentation? – Suraj Aug 26 '11 at 14:32
  • 2
    When I tested in the roxygen (0.1-2) and the roxygen2 (2.1), `@method` + `@export` is NOT equivalent to `@S3method` as SFun28 said. `@S3method` did not generate \method entries. I think that both tags are required in the roxygen (0.1-2) and the roxygen2 (2.1). – Triad sou. Aug 29 '11 at 00:41
  • Triad - Thanks for help out! +1 Your solution works great. It seems that you can leave out "@return \code{NULL}" and it works just fine too. Marking yours as answer. Questions to Hadley are still open. – Suraj Aug 29 '11 at 18:32
  • +1. Worked fine and had been having trouble with this. Need to be careful that each function has its own `@rdname` and either `@export` or `@method`/`@S3method` – dardisco Sep 02 '13 at 04:22
  • 10
    For anyone still coming here years later, as of Roxygen2 6.0.1 `@S3method` is deprecated and gives `Warning: script.R:302: @S3method is deprecated. Please use @export instead`. `@method` + `@export` does the trick. `R CMD check` still complains about just using `@export`, though. – Scott Gigante May 23 '18 at 05:01
  • 1
    As of `roxygen2-7.1.1`, no recommendation is given, just `@S3method unknown tag`. Instead, I've found using `@exportS3Method generic class` works. – r2evans Aug 26 '21 at 17:36
  • Hey Guys, for beginners like me it wouldn't hurt to mention, that writing simply `@method generic method` and `@export` aren't enough to test if it worked or not. after doing so, you also need to build the documentation and use `devtools::load_all(".")` again to let the declaration as a s3 method take effect in real code :P - just a beginner here, so please bear with me. – y3kMyRon Mar 25 '22 at 08:02