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

From: Oosting, J. (PATH) <>
Date: Wed 13 Sep 2006 - 20:36:26 GMT

I have tried it on the patched version of R, and it works now.  



Van: John Chambers [] 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)

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


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.


	[1] "gt.barplot"
	[1] "globaltest"


	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")


	Function: plot, (package graphics)
	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.


	R version 2.4.0 alpha (2006-09-11 r39258) 
	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" 
	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. 

	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
		Loading required package: minipkg2
		Creating a new generic function for 'plot' in 'minipkg2'
		Error in as.vector(x, "double") : cannot coerce to vector
			plot(mpplot(1:10,plot=FALSE)) # this shows a proper plot
		Function: plot, (package graphics)
		R version 2.4.0 Under development (unstable) (2006-09-04 r39086) 
		attached base packages:
		[1] "methods"   "stats"     "graphics"  "grDevices" "utils"
		[7] "base"     
		other attached packages:
		 minipkg minipkg2 
		 "1.0.0"  "1.0.0" 
			______________________________________________ mailing list
		[[alternative HTML version deleted]]
	______________________________________________ mailing list

	[[alternative HTML version deleted]]

______________________________________________ mailing list Received on Thu Sep 14 06:48:37 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 Thu 14 Sep 2006 - 01:30:06 GMT.

Mailing list information is available at Please read the posting guide before posting to the list.