RE: [Rd] UseMethod call with no arguments - solved, I think

From: Henrik Bengtsson <hb_at_maths.lth.se>
Date: Sat 20 Nov 2004 - 06:40:25 EST


> -----Original Message-----
> From: r-devel-bounces@stat.math.ethz.ch
> [mailto:r-devel-bounces@stat.math.ethz.ch] On Behalf Of Prof
> Brian Ripley
> Sent: Tuesday, November 16, 2004 1:36 PM
> To: Henrik Bengtsson
> Cc: R-devel@r-project.org
> Subject: RE: [Rd] UseMethod call with no arguments - solved, I think
>

> > My concern/interpretation was that
> >
> > bar <- function(...) UseMethod("bar")
> >
> > is deprecated (where I saw "..." as the "arguments"). Reading
> > ?UseMethod
>
> I don't read that as being supported, and it does not work in
> S. `...' is
> not strictly an argument of a function, and is usually documented as
> `further arguments'.
>
> > more carefully (it still says) - "If it is called with just one
> > argument, the class of the first argument of the enclosing
> function is
> > used as
> > 'object': unlike S this is the actual argument passed and
> not the current
> > value of the object of that name." - I see that the above
> should still be
> > fine.
>
> > So, now the note makes perfectly sense and it is *not* a "big step".
>
> However, removing undocumented features can happen at any
> time. There is
> danger in using unusual constructions that may be allowed
> according to
> some particular reading of some of the documentation. In particular,
> consider the following
>
> > bar <- function(..., x) UseMethod("bar")
> > bar.foo <- function(..., x) print("foo")
> > x <- structure(1, class="foo")
> > bar(x) # arg is part of ...
> [1] "foo"
> > bar(x=x) # arg is matched to x
> [1] "foo"
> > bar(1, x=x)
> Error in bar(1, x) : no applicable method for "bar"

...and you wish to dispatch on 'x', which *can* be done with UseMethod("bar", x")? In S3, where you can only dispatch on *one* object, is there really a rational for *not* putting the object as a first argument? Maybe...

For curiosity, I grepped the R v2.0.1 source for occurances where UseMethod() is called with more than the one argument. Then I search for those generic function who does not dispatch based on the first argument. The result is:

% cd src/library/
% grep 'UseMethod(' */R/*.R | wc -l

  232 # nbr of usage of UseMethod

% grep -h -B 2 -E "^[ ]*[^#].*UseMethod[(][ ]*[\"'][^\"']*[\"'][ ]*[,]" */R/*.R

widthDetails <- function(x) {
  UseMethod("widthDetails", x)

--

heightDetails <- function(x) {
  UseMethod("heightDetails", x)

Recommended packages:
% for f in Recommended/*.tar.gz; do gunzip -c $f | tar -xO | grep -E "^[
]*[^#].*UseMethod[(][ ]*[\"'][^\"']*[\"'][ ]*[,]"; done

loglm1 <- function(formula, data, ...) UseMethod("loglm1", data)

So, only three generic functions in R distribution call UseMethod() with
more than one argument, and one of these are dispatching on the second
argument, not the first. The others call UseMethod() with one arguments,
maybe for the same reason as I will use below; minimize redundancy => easier
to maintain and less risk for bugs.

Continuing...

CRAN (419 packages):
The script and complete output is attached. 

I found the following packages (bundles were not checked) and generic
functions dispatching on another argument than the first (indeed, all on the
2nd):

Zeilig: sim <- function(object, x, ...) UseMethod("sim", x) 
ipred: bagging <- function(formula, data, ...) UseMethod("bagging", data) 
ipred: errorest <- function(formula, data, ...) UseMethod("errorest", data) 
ipred: inbagg <- function(formula, data, ...) UseMethod("inbagg", data) 
ipred: inclass <- function(formula, data, ...) UseMethod("inclass", data) 
maxstat: maxstat.test <- function(formula, data, ...)
UseMethod("maxstat.test", data)

Indeed, there are a few method dispatching on the 2nd argument. 

Interestingly, almost all of these seem to have a 'formula' as the first
argument and a data object as a second, which they dispatch on. This, was
actually the only case I could think of that would make sense; the 'formula'
object is somewhat more "important" than the 'data' object and is therefore
put first.

Your last call of your next example demonstrates a potential problem for the
above methods;


> > bar <- function(y, x, ...) UseMethod("bar")
> > bar(x) # matches y
> [1] "foo"
> > bar(x=x) # matches x
> [1] "foo"
>
> and I don't think there is any intention that such behaviour will
> necessarily continue (the last one does look like an error). The
> rules seem not to be written down clearly enough.'
Yes, it definitely looks like an error. However, of the above identified generic functions, will they be called without the first argument? I would say, probably not. However, you can always argue that the user may swap the order;
> y=1
> bar(x=x, y=y) # matches x
which is a *real* problem I would say. In the real world (the methods with 'formula' found above), that could be a problem, but I do not think it would be hard to be explicit about this in the documentation/help. There is of course a reason for why I put time on this, and it is because I find extremely useful to write my generic function as generic <- function(...) UseMethod("generic") This way I leave it open do *anyone* to use whatever arguments they want in their 'generic.Class' methods (in case they have one of my package loaded). Now I learned to add "...as long as they assume dispatching on the first argument". Doing will minimize the risk for naming conflicts between existing packages (that I do not know of, and of my packages that others do not know of), between existing and future packages, between existing packages and future added/modified core functions in R etc. Also, if I want to use a generic function called 'foo()', but there already exists another function (or generic function) in another package (or in R) identically named, then it is possible to test for this, try to redefine the existing generic function etc, and replace it with the above construct. My (internal) setGenericS3() in R.oo, which is called by setMethodS3(), does this. Since I started to use setMethodS3() for *all* (hundreds, maybe thousands) of my method definitions including default function, that is, since spring 2001, I *never* had to update a single method because of naming conflicts or argument conflicts. I can use my hours for other things (as working on Friday evening ;) ). (The only thing "issue" is that R CMD CHECK of course complains about mismatching arguments between generic functions and other). Best wishes Henrik
> --
> Brian D. Ripley, ripley@stats.ox.ac.uk
> Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/
> University of Oxford, Tel: +44 1865 272861 (self)
> 1 South Parks Road, +44 1865 272866 (PA)
> Oxford OX1 3TG, UK Fax: +44 1865 272595

______________________________________________ R-devel@stat.math.ethz.ch mailing list https://stat.ethz.ch/mailman/listinfo/r-devel

Received on Sat Nov 20 07:22:45 2004

This archive was generated by hypermail 2.1.8 : Sat 20 Nov 2004 - 08:10:54 EST