Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

S3methods in NAMESPACE not exported

I am developing an R package using devtools::document() to create the NAMESPACE file. Several of the functions are S3methods for summary, predict, plot, print where the generic is in base or stats. I am using @export as Hadley recommends and that leads to the correct S3method entry in the NAMESPACE, and the package passes all checks -as-cran. The functions are not exported in the NAMESPACE, however, so calling print.myclass is not found (I understand that is the desired behavior to avoid cluttering up the NAMESPACE). However, calling the function by Mypackage::print.myclass also leads to an error that the function is not an exported object from Mypackage.

Question: is that the correct behavior? Or are there other steps needed to have the function exported? I have tried adding both @method print Myclass and @export but with no luck. Using R 3.4.2 with devtools 1.13.3 under MAC OS X 10.12.6

Thanks! Merlise

Edited: updated to have the code that will add/export method and export function

Simple example - build a skeleton package in RStudio with function:

#' test for export of S3 methods
#'
#' @title "print hello world for any object"
#' @param x object
#' @param digits optional number specifying the number of digits to display
#' @param ... other parameters to be passed to \code{print.default}
#' @export print.hello
#' @export
print.hello = function (x, digits = max(3, getOption("digits") - 3), ...)
{
  cat("\n Hello World \n")
  invisible()
}

The NAMESPACE now has

# Generated by roxygen2: do not edit by hand

S3method(print,hello)
export(print.hello)

Using @export with no arguments exports the method while @export print.hello exports the function, but does not add the method to the NAMESPACE (which would lead to an error with the package check). Having both would allow the method and the function to be exported.

like image 855
Merlise Clyde Avatar asked Oct 27 '17 01:10

Merlise Clyde


2 Answers

First of all, in order to formally define a S3 method and export it properly without manually changing the namespace file (assuming you are using roxygen),

#' test for export of S3 methods
#'
#' @title "print hello world for any object"
#' @param x object
#' @param digits optional number specifying the number of digits to display
#' @param ... other parameters to be passed to \code{print.default}
#'
#' @rdname print
#' @export print
print <- function(x, ...){
  UseMethod("print")
}

#' @rdname print
#' @export print.hello
#' @export
print.hello <- function (x, digits = max(3, getOption("digits") - 3), ...)
{
  cat("\n Hello World \n")
  invisible()
}

This more or less gives you the expected behavior for testPackage::print.hello. The more important thing here is to understand what exactly S3 method is for. It is used for method dispatching in R and the suffix after . should always stand for the class of object you are supposed to put in as the first argument of the function. That is, in this case, if you want to use print.hello with a single call of print, you would have to put a class of hello, try the example below after you successfully build and load the testpackage

a = 1
print(a) # method dispatched as print.default because class of a is numeric
# 1  
class(a) <- 'hello'
print(a) # method dispatched as print.hello
# Hello World 
like image 113
platypus Avatar answered Nov 09 '22 14:11

platypus


This is the correct behaviour for your NAMESPACE file. :: accesses exported variables, so testPackage::print.hello should fail. ::: accesses internal variables, so testPackage:::print.hello should work for you.

like image 2
Luke Tierney Avatar answered Nov 09 '22 14:11

Luke Tierney