2

I am trying to understand this R CMD check warning for S3 function.

So, here is a completely reproducible example of my situation including R code and roxygen code. (I can never find a complete example of S3 anywhere and real-world usage in packages are either overly complicated or poorly documented. So, hopefully this is helpful to others implementing S3.)

#' @title An S3 generic.
#' @description An S3 generic that does something.
#' @param obj A numeric or character class object..
#' @param ... Other parameters are passed to methods.
#' @return Does something.
#' @export
#'
do_something <- function(obj, ...) {
  if(!class(obj) %in% c("numeric","character")) stop("obj must be character or numeric class.")
  UseMethod("do_something",obj)
}

#' @title An S3 method for obj class numeric.
#' @description An S3 method for obj class numeric.
#' @param obj A numeric class.
#' @param summary A character string.
#' @return Returns something.
#' @method do_something numeric
#' @rdname do_something.numeric
#' @importFrom stats median
#' @export
#' 
do_something.numeric <- function(obj, summary="mean") {
  
  if(summary=="mean") x <- mean(obj)
  if(summary=="median") x <- median(obj)
  
  return(x)
}

#' @title An S3 method for obj class character.
#' @description An S3 method for obj class character.
#' @param obj A character class.
#' @param collapse A character string.
#' @return Returns something.
#' @method do_something character
#' @rdname do_something.character
#' @export
#' 
do_something.character <- function(obj, collapse=",") {
  return(paste(obj,collapse=collapse))
}

I have an S3 generic do_something() that dispaches to method functions do_something.numeric() or do_something.character() based on the obj class. There are two method functions for the two different classes. And apart from the common shared argument obj, they have distinct arguments themselves.

The functions work as intended, but running R CMD check on this returns this.

> checking S3 generic/method consistency ... WARNING
  do_something:
    function(obj, ...)
  do_something.character:
    function(obj, collapse)
  
  do_something:
    function(obj, ...)
  do_something.numeric:
    function(obj, summary)
  
  See section ‘Generic functions and methods’ in the ‘Writing R
  Extensions’ manual.

0 errors ✓ | 1 warning x | 0 notes ✓
Error: R CMD check found WARNINGs
Execution halted

Exited with status 1.

Now, I can fix this warning by adding , ... to method functions as well as the roxygen part. Here is the fixed code.

#' @title An S3 generic.
#' @description An S3 generic that does something.
#' @param obj A numeric or character class object..
#' @param ... Other parameters are passed to methods.
#' @return Does something.
#' @export
#'
do_something <- function(obj, ...) {
  if(!class(obj) %in% c("numeric","character")) stop("obj must be character or numeric class.")
  UseMethod("do_something",obj)
}

#' @title An S3 method for obj class numeric.
#' @description An S3 method for obj class numeric.
#' @param obj A numeric class.
#' @param summary A character string.
#' @param ... Other parameters
#' @return Returns something.
#' @method do_something numeric
#' @rdname do_something.numeric
#' @importFrom stats median
#' @export
#' 
do_something.numeric <- function(obj, summary="mean", ...) {
  
  if(summary=="mean") x <- mean(obj)
  if(summary=="median") x <- median(obj)
  
  return(x)
}

#' @title An S3 method for obj class character.
#' @description An S3 method for obj class character.
#' @param obj A character class.
#' @param collapse A character string.
#' @param ... Other parameters
#' @return Returns something.
#' @method do_something character
#' @rdname do_something.character
#' @export
#' 
do_something.character <- function(obj, collapse=",", ...) {
  return(paste(obj,collapse=collapse))
}

But, why!!??

To my understanding, the ... in the generic is meant to signify additional arguments being passed to any of the method functions. In this case, ... stands for arguments summary and/or collapse. And adding ... makes sense to me if I had another internal function inside my method function like this.

do_something.character <- function(obj, collapse=",", ...) {
  x <- an_internal_function(obj=obj, collapse=collapse, ...)
  return(x)
}

But, I have no additional arguments to pass, so why do I need the ... and what does it do here? Hopefully someone can clarify this.

R_4.0.0

mindlessgreen
  • 11,059
  • 16
  • 68
  • 113
  • 1
    Did you look at "‘Generic functions and methods’ in the ‘Writing R Extensions’ manual" as the warning suggested? You can find it here: https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Generic-functions-and-methods It says "A method must have all the arguments of the generic, including … if the generic does." – duckmayr Dec 29 '20 at 14:55
  • try `do_something(c(1, 2), summary = 'mean')` and `do_something(c('1', '2'), summary = 'mean')` with and without dots – rawr Dec 29 '20 at 17:38

0 Answers0