Can't fix warning when redefining log as a generic - r

I would like to make the log function a generic so that I can alter it's behavior under some newclass.
I have a minimal package with a DESCRIPTION file:
Package: logmethod
Type: Package
Title: A new Log Method
Version: 0.1
Date: 2017-03-23
Author: Me
Maintainer: Who to complain to <yourfault#somewhere.net>
Description: More about what it does (maybe more than one line)
License: MIT
LazyData: TRUE
RoxygenNote: 5.0.1
And the R Code, based on what I've learned at Writing R Extensions and Is it bad style to redefine non-S3 base functions as S3 functions in an R package?
#' #name log_method
#' #title A New Log Method
#'
#' #description A new \code{log} method
#'
#' #param x a numeric, complex, or measured variable
#' #param base a positive or complex measured variable: the base with respect to which
#' logarithms are computed. Defaults to \emph{e}=\code{exp(1)}.
#' #param ... Additional arguments to pass to other methods.
#'
#' #export
log <- function(x, base, ...)
{
UseMethod("log")
}
#' #rdname log_method
#' #export
log.default <- function(x, base, ...)
{
base::log(x, base)
}
#' #rdname log_method
#' #export
log.newclass <- function(x, base, ...)
{
print("See, it dispatched")
log.default(as.numeric(x), as.numeric(base), ...)
}
When I run check, I keep getting the warning
checking S3 generic/method consistency ... WARNING
Warning: declared S3 method 'log.default' not found
Warning: declared S3 method 'log.newclass' not found
See section 'Generic functions and methods' in the 'Writing R
Extensions' manual.
When I install the package, I'm able to use log.default and log.newclass, so I'm not sure how to interpret this warning that the methods are not found. Turning an R S3 ordinary function into a generic describes how to make an S4 function, but I'd like to stick to S3 if possible. I would love to know why I keep getting this warning.
EDIT:
The NAMESPACE might also be useful.
# Generated by roxygen2: do not edit by hand
S3method(log,default)
S3method(log,newclass)
export(log)

It turns out the piece of the puzzle I was missing is that log and most of its cousins are already generic. From the ?log documentation details
All except logb are generic functions: methods can be defined for them
individually or via the Math group generic.
Thus, the proper coding for the new methods would have been the following (notice the lack of a UseMethod call)
log.default <- function(x, base, ...)
{
base::log(x, base)
}
log.newclass <- function(x, base, ...)
{
print("See, it dispatched")
log.default(as.numeric(x), as.numeric(base), ...)
}
On the other hand, since logb is not defined as a generic, that is a case where the instructions in Writing R Extensions would have been relevant (because dispatch is not yet designed)
logb <- function(x, base, ...)
{
UseMethod("logb")
}
logb.default <- function(x, base, ...)
{
base::logb(x, base)
}
logb.newclass <- function(x, base, ...)
{
print("See, it dispatched")
logb.default(as.numeric(x), as.numeric(base), ...)
}
So if you're coming across an warning like in the question, it may be worth checking into whether or not the base version of the function isn't already a generic.

Related

S4 error: methods can be defined, but the generic function is implicit, and cannot be changed

I'm creating the following method via S4
#' #name +
#' #title Expand outputs
#' #description
#'
#' Operator outputs of function 'create'
#'
#' #return expanded creation
#' #exportMethod +
#' #aliases +
#' #export
setGeneric('+', function(dt, ...) standardGeneric('+'))
setMethod('+', signature(dt = 'data.table'), function(dt, out) {
return(create(dt, out))
})
I put the following into my R package. When I run devtools::document(), I run into the following problem:
Error in setGeneric("+", function(dt, ...) standardGeneric("+")) :
‘+’ dispatches internally; methods can be defined, but the generic function is implicit, and cannot be changed.
This appears to be a fatal error, and I cannot create documentation otherwise.
(1) What does this error mean? I'm unsure how I'm supposed to debug this.
(2) When creating an R package, what would be the correct way to work with this error? Should I create the documentation first with another name besides + and then change this afterwards?
As a builtin function, the definition of the generic + cannot be changed, as the error message says. Much of R would break if you did redefine it this way.
+ is defined to have two arguments, e1 and e2. Using this framework, you can modify your example to be
setMethod('+', signature(e1 = 'data.table', e2='ANY'), function(dt, out) {
return(create(dt, out))
})
One thing to note is that e1 is always the first argument, even if argument names are used. so "+"(e2=A,e1=B) is equal to A+B, not B+A.

Export error on overwriting primitives with S3 in R package

I'm trying to create a S3 method in my package called dimnames. This is a primitive in R, but there should be an S3 in my package with the same name.
I've got the following file dimnames.r
#' S3 overwriting primitive
#'
#' #param x object
#' #export
dimnames = function(x) {
UseMethod("dimnames")
}
#' title
#'
#' #export
dimnames.data.frame = function(x) {
dimnames.default(x)
}
#' title
#'
#' #export
dimnames.list = function(x) {
lapply(x, dimnames)
}
#' title
#'
#' #export
dimnames.default = function(x) {
message("in S3 method")
base::dimnames(x)
}
I then create a package from it (in R=3.3.2):
> package.skeleton("rpkg", code_files="dimnames.r")
> setwd("rpkg")
> devtools::document() # version 1.12.0
And then check the package
R CMD build rpkg
R CMD check rpkg_1.0.tar.gz
I get the following output (among other messages):
Warning: declared S3 method 'dimnames.default' not found
Warning: declared S3 method 'dimnames.list' not found
Loading the package and checking its contents, dimnames.data.frame is exported while dimnames.default and dimnames.list are not. This does not make sense to me. As far as I understand, I declared the exports correctly. Also, the NAMESPACE file looks good to me:
S3method(dimnames,data.frame)
S3method(dimnames,default)
S3method(dimnames,list)
export(dimnames)
Why does this not work, and how to fix it?
(Bonus points for: why do I need #' title in the S3 implementations when they should not be needed with roxygen=5.0.1?)
S3 methods are only exported if it is desired that the user be able to access them directly. If they are always to be invoked via the generic then there is no need to export them.
The problem with R CMD check is likely due to defining your own generic for dimnames. Normally one just defines methods and leverages off the primitive generic already in R. Remove the dimnames generic from dimnames.r.
There should be no problem in adding methods for new classes but you may have problems trying to override the functionality of dimnames for existing classes that R's dimnames handles itself.

R-oxygen documentation of S3 method produces error while check [duplicate]

I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.

New method for plot - how to export?

I am making a package where I want to define a new method for plot. I am using roxygen in-source documentation. This question seems very similar to:
How to properly document a S3 method of a generic from a different package, using Roxygen?
and
Roxygen2 - how to properly document S3 methods
but I still cannot get it to work.
The relevant parts that are causing me trouble are:
#' Generic plot method
#'
#' #param x \dots
#' #param ... \dots
#' #export
plot <- function(x, ...) UseMethod("plot")
#' Default plot method
#'
#' #param x \dots
#' #param ... \dots
#' #importFrom graphics plot
#' #method plot default
#' #S3method plot default
plot.default <- function(x, ...) graphics::plot(x, ...)
#' Plotting function for ABI object
#'
#' Description.
#'
#' #param x ABI object as generated by newABI.
#' #param base Character. Bases to look at.
#' #param ... Other options passed to plot().
#' #return Nothing. Side-effect: plots graphs.
#' #method plot ABI
#' #S3method plot ABI
plot.ABI <- function(x, base, ...) {
#Overly simplified
plot(1, 1, main = base)
}
When I run this and investigate methods(plot), there is no method defined for ABI objects. Accessing the function by ABI:::plot (ABI is the name of the package) does work. Using :: does not.
During the package build check, there is a warning:
* checking S3 generic/method consistency ... WARNING
plot:
function(x)
plot.ABI:
function(x, base, ...)
See section ‘Generic functions and methods’ of the ‘Writing R
Extensions’ manual.
It seems that there is a disagreement in arguments. But I don't understand this, since the generic has arguments x and ... and so does my ABI method (in addition to base).
So there are two problems, which I hope stem from the same issue: The plot.ABI method is not exported and the package check throws a warning.
How do I solve this?
The problem is that your method needs to have the same arguments as the generic. Let's assume you are using the generic supplied with R:
> args(plot)
function (x, y, ...)
NULL
Now plot() is actually a special case as you can essentially ignore that there is an argument y there.
So your method needs to be as you have it:
plot.ABI <- function(x, base, ...)
The issue is that, contrary to your quoted script, you must have redefined the generic as
plot(x)
and as that is missing ..., R CMD check will rightly complain.
So, don't document or provide the generic if it already exists.
A few problems:
Don't include a generic that is already defined elsewhere. Just add your method.
The signatures of every method must at least include every element in the generic, in the same order. It's annoying sometimes, but it's incontrovertible.
Update
I had said, "Your #export needs to list the function name," but apparently this is not correct. See the comments. Note also that listing the method should export it. I seem to recall needing an explicit export in cases where you aren't including the generic in your package's namespace, but I could be wrong (so often am!).

How to properly document a S3 method of a generic from a different package, using Roxygen?

I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.

Resources