S3 generics need identical signature?

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

S3 generics need identical signature?

Gábor Csárdi-2
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?

Thanks, Best Regards,
Gabor

--
Gabor Csardi <[hidden email]>     UNIL DGM

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: S3 generics need identical signature?

Duncan Murdoch-2
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

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: S3 generics need identical signature?

Gábor Csárdi-2
On Mon, Jun 21, 2010 at 4:17 PM, Duncan Murdoch
<[hidden email]> wrote:
[...]
> 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.

This makes sense, and it is actually great! Thanks a lot for the explanation.

Best Regards,
Gabor

[...]


--
Gabor Csardi <[hidden email]>     UNIL DGM

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: S3 generics need identical signature?

Henrik Bengtsson
On Mon, Jun 21, 2010 at 4:23 PM, Gábor Csárdi <[hidden email]> wrote:

> On Mon, Jun 21, 2010 at 4:17 PM, Duncan Murdoch
> <[hidden email]> wrote:
> [...]
>> 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.
>
> This makes sense, and it is actually great! Thanks a lot for the explanation.

FYI, the most "generic" way you can write a generic function is:

foo <- function(...) UseMethod("foo");

/Henrik

>
> Best Regards,
> Gabor
>
> [...]
>
>
> --
> Gabor Csardi <[hidden email]>     UNIL DGM
>
> ______________________________________________
> [hidden email] 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.
>

______________________________________________
[hidden email] 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.
Reply | Threaded
Open this post in threaded view
|

Re: S3 generics need identical signature?

Thomas Lumley
On Mon, 21 Jun 2010, Henrik Bengtsson wrote:

> On Mon, Jun 21, 2010 at 4:23 PM, Gábor Csárdi <[hidden email]> wrote:
>> On Mon, Jun 21, 2010 at 4:17 PM, Duncan Murdoch
>> <[hidden email]> wrote:
>> [...]
>>> 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.
>>
>> This makes sense, and it is actually great! Thanks a lot for the explanation.
>
> FYI, the most "generic" way you can write a generic function is:
>
> foo <- function(...) UseMethod("foo");
>
This is only the "most generic" way if you want dispatch on the first argument.  You can have dispatch on a different argument, and that requires you to specify arguments to the generic function.

For example, I have written quite a few functions of the form
    foo <- function(formula, data, ...) UseMethod("foo", data)


         -thomas

Thomas Lumley Assoc. Professor, Biostatistics
[hidden email] University of Washington, Seattle

______________________________________________
[hidden email] 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.