Re: [Rd] S4 Method dispatch in recent 2.4.0alpha

From: John Chambers <jmc_at_r-project.org>
Date: Wed 13 Sep 2006 - 18:34:06 GMT

Although there is not enough information to be sure, this may be related to an issue uncovered in other testing, for which a patch has just been committed.

The issue arises if the same generic function is defined in several packages. For example, Matrix and msbase both have methods for the plot() function in graphics. Since that function is not a generic, creating methods causes a generic function to be saved in the two packages' export environment.

So attaching both packages gives 3 versions of plot(), two generic and one not.

 > find("plot")
[1] "package:msbase" "package:Matrix" "package:graphics"

Note that this is NOT a question of having DIFFERENT generics with the same name; both these generics have package slot equal to "graphics" and therefore they refer to the same function.

The issue that arose was that, while a cached generic for plot() had all the methods, the methods table in the individual packages generally did not. So here, a call to plot() picks up the generic from msbase, which may not have the methods defined in Matrix. The symptom is that plot(x) from the global environment fails to find a method, say for "coef.lmer" defined in Matrix, even though showMethods("plot") and selectMethod("plot", "coef.lmer") show the method.

The version committed today copies the cached version of the generic into the exported environment of the individual packages, so that all methods are available regardless of the order of the packages in the search list.

Again, remember that this is only when the package slot matches. The following should work, although the sanity of the programmer is in doubt.

 > plot <- function(theta) theta+1
 > setGeneric("plot", package="myPackage", function(theta)standardGeneric("plot"))
[1] "plot"
 > showMethods("plot")
Function: plot (package myPackage)
theta="ANY"

The user now would have to disambiguate:

 > Matrix::plot(1:10)
Hit <Return> to see next plot:
 > plot(1:10)
 [1] 2 3 4 5 6 7 8 9 10 11

The programmer should usually set up the imports for a package so that there is no ambiguity about which version is meant. Also, with 2.4.x one should be able to supply the generic _function_ rather than just its name as the argument to setMethod(). But it's not claimed that something like the above works completely as one would expect.

The caching mechanism only applies to globally visible generic functions. At the moment, non-exported (and so private) versions of a generic like plot are not cached. Primitives unfortunately are always global.

There's some related discussion on the web page http://developer.r-project.org/howMethodsWork.pdf

John

One more comment: For the future, I believe that the right attitude is that there is one version of this generic function, and it lives in the "graphics" package (yet one more time, _this_ generic function, identified by its name and package slot). However, to implement that view cleanly needs a couple of things we don't have:

  1. a centralized dispatch for all generic functions, somewhat as is done now for primitives.
  2. methods labeled by the full reference to the classes--the class name plus the package where the definition of the class exists. Otherwise, we can't be completely general about method selection. Right now the system does not allow the same generic to have _public_ methods for two classes of the same name.

These changes are a bit too much for the few weeks left for 2.4.0.

Oosting, J. (PATH) wrote:
> Your suggestions worked ok in the example, but in my case there is yet another package that implements a plot method.
> Now the plotting from within the package works, but plotting from outside the package, on the console, gives an error as if plot.default is invoked.
>

>> class(myplot)
>>     

> [1] "gt.barplot"
> attr(,"package")
> [1] "globaltest"
>
>> plot(myplot)
>>     

> Error in xy.coords(x, y, xlabel, ylabel, log) :
> 'x' and 'y' lengths differ
> >

> Rgraphviz implements a plot method on 2 classes: graph and Ragraph
> multtest implements a plot method on 1 class: MTP
>

> globaltest, the package i'm working on, depends on multtest, and suggests Rgraphviz. Class gt.barplot implements a plot method
>
>

> the output of showMethods("plot")
>
>> showMethods("plot")
>>     

> Function: plot, (package graphics)
> x="ANY"
> x="graph"
> x="gt.barplot"
> x="MTP"
> x="Ragraph"
>

> Rgraphviz has a proper NAMESPACE and I created one for multtest that imports plot from graphics, and exports plot as a method, because they are not dependent on each other that does seem ok.
> In globaltest I import the plot method from multtest.
>

> How to deal with this.
>

>
>> sessionInfo()
>>     

> R version 2.4.0 alpha (2006-09-11 r39258)
> i386-pc-mingw32
>

> locale:
> LC_COLLATE=Dutch_Netherlands.1252;LC_CTYPE=Dutch_Netherlands.1252;LC_MONETARY=Dutch_Netherlands.1252;LC_NUMERIC=C;LC_TIME=Dutch_Netherlands.1252
>

> attached base packages:
> [1] "splines" "tools" "methods" "stats" "graphics" "grDevices"
> [7] "utils" "datasets" "base"
>
> other attached packages:
> Rgraphviz geneplotter GOstats Category hgu95av2 genefilter
> "1.11.10" "1.11.8" "1.7.11" "1.5.9" "1.13.0" "1.11.8"
> RBGL annotate graph Ruuid GO KEGG
> "1.9.9" "1.11.5" "1.11.14" "1.11.2" "1.13.0" "1.13.0"
> hu6800 globaltest multtest survival vsn golubEsets
> "1.13.0" "4.3.5" "1.11.2" "2.28" "1.11.2" "1.3.1"
> Biobase
> "1.11.34"
>
>

> ===========================================================
> John Chambers wrote:
>
>> Good example.
>>
>> The basic problem is in the NAMESPACE file:
>>
>> importFrom(graphics, plot)
>>
>> But the version of plot() in the graphics package is not a generic function.  Therefore, when your mpplot() calls it there is no >method dispatch.
>>
>> You need to import the generic version of plot() from minipkg2 (notice that there's a message about creating a new generic for >plot() when you install minipkg2).
>>
>> The line in the NAMESPACE file should be:
>>
>> importFrom(minipkg2, plot)
>>
>> In your mini-example, there are some additional steps needed, not directly related to the problem & possibly not true in the >real example.
>>
>> 1.  minipkg2 also needs a NAMESPACE, in which it imports from methods and graphics and exports plot and the class mp2.plot >(example attached).
>>
>> 2.  Highly recommended though maybe not required here is to use some form of saved image, e.g. by including "LazyLoad:yes" in >the two DESCRIPTION files. 
>>
>> John
>>     
>
>

> Oosting, J. (PATH) wrote:
>

> I use 2 packages that both implement a S4 plot method, where one package
> depends on the other (the bioconductor package globaltest which depends
> on multtest). When the plot method is used from within the package, it
> seems the default plot method is used, and an error is generated. When
> the method is invoked from the console, the plot is created correctly. I
> have reproduced this with 2 small packages (minipkg and minipkg2)
> implementing just this part.
> I've seen a thread about a similar problem, but that seemed mostly due
> to already installed packages not handling the new S4 stuff.
>
> mpplot() is a function that creates a class instance and (usually)
> invokes the plot immediately. When the dependency on minipkg2 is removed
> from the DESCRIPTION file the first call to mpplot() gives no error and
> shows the plot.
>
>
> Jan Oosting
>
>
>

> library(minipkg)
>
>

> Loading required package: minipkg2
> Creating a new generic function for 'plot' in 'minipkg2'
>
>

> mpplot(1:10)
>
>

> Error in as.vector(x, "double") : cannot coerce to vector
>
>

> plot(mpplot(1:10,plot=FALSE)) # this shows a proper plot
> showMethods("plot")
>
>

> Function: plot, (package graphics)
> x="ANY"
> x="mp.plot"
> x="mp2.plot"
>
>

> sessionInfo()
>
>

> R version 2.4.0 Under development (unstable) (2006-09-04 r39086)
> i386-pc-mingw32
>
> locale:
> LC_COLLATE=Dutch_Netherlands.1252;LC_CTYPE=Dutch_Netherlands.1252;LC_MON
> ETARY=Dutch_Netherlands.1252;LC_NUMERIC=C;LC_TIME=Dutch_Netherlands.1252
>
> attached base packages:
> [1] "methods" "stats" "graphics" "grDevices" "utils"
> "datasets"
> [7] "base"
>
> other attached packages:
> minipkg minipkg2
> "1.0.0" "1.0.0"
>
>

>
>
> ________________________________
>
>

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

> [[alternative HTML version deleted]]
>
> ______________________________________________
> R-devel@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

        [[alternative HTML version deleted]]



R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Thu Sep 14 04:37:22 2006

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.1.8, at Wed 13 Sep 2006 - 21:30:07 GMT.

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