Re: [R] S3 generics need identical signature?

From: Duncan Murdoch <murdoch.duncan_at_gmail.com>
Date: Mon, 21 Jun 2010 10:17:14 -0400

On 21/06/2010 9:31 AM, Gábor Csárdi wrote:
> Dear all,
>
> "Writing R Extensions" explicitly says that
>
> A method must have all the arguments of the generic, including ...
> if the generic does.
> A method must have arguments in exactly the same order as the generic.
> If the generic specifies defaults, all methods should use the same
> defaults.
>
> This is clear. R CMD check even checks for this.
>
> But then how is it possible that for plot(), which is an S3 generic,
> plot.default(), plot.formula() and plot.table(), etc. all have
> different arguments?
>
> The question is not simply theoretical, I have two S3 generics in my
> package, and one is reported by R CMD check, but the other not, and I
> fail to see why the difference.
>
> Moreover, R CMD check reports:
> * checking S3 generic/method consistency ... WARNING
> plot:
> function(x, ...)
> plot.communities:
> function(communities, graph, colbar, col, mark.groups, layout,
> edge.color, ...)
>
> But actually, the signature of plot() seems to be
> > plot
> function (x, y, ...)
> [...]
>
> I am confused. What am I missing?

The requirement is that the methods need to have signatures that contain all the arguments of the generic. If the generic includes ..., then the methods can add other arguments, too. So with the generic for plot() as you show above, any plot method is required to have x and y as the first two arguments, and ... as an argument, but they can have other args too. Looking at them:

head(plot.default)

1 function (x, y = NULL, type = "p", xlim = NULL, ylim = NULL,             
2     log = "", main = NULL, sub = NULL, xlab = NULL, ylab = NULL,         
3     ann = par("ann"), axes = TRUE, frame.plot = axes, panel.first = NULL,
4     panel.last = NULL, asp = NA, ...)               


This is okay.

head(graphics:::plot.formula)
1 function (formula, data = parent.frame(), ..., subset, ylab = varnames[response],
2 ask = dev.interactive())

This violates the rule, so if someone does this:

y <- rnorm(10)
x <- 1:10
formula <- y ~ x
plot(formula)

they'll get what they want, but

plot(x = formula)

they'll get an obscure error message:

 > plot(x=formula)
Error in terms.formula(formula, data = data) :   argument is not a valid model

head(graphics:::plot.table)
1 function (x, type = "h", ylim = c(0, max(x)), lwd = 2, xlab = NULL, 2 ylab = NULL, frame.plot = is.num, ...)

This also violates the rule, but it's hard to think of an example where it might cause trouble.

HOWEVER, plot() is a very old function, and methods were written for it long before the current rule was established. So it is handled specially by the check code.
The y argument is not required (see the checkArgs code in src/library/tools/R/QC.R), and apparently the first arg doesn't need to be named x in plot.formula, due to some other exception which I can't spot right now. So I would not use the base code for plot() as an example of what you should do.

Duncan Murdoch



R-help_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code. Received on Mon 21 Jun 2010 - 14:20:34 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Mon 21 Jun 2010 - 15:00:33 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-help. Please read the posting guide before posting to the list.

list of date sections of archive