I have encountered an issue which I have been unable to resolve, involving an S3 generic (print) being declared S4 generic in a package, and the method being exported. This all works fine - the problem occurs when I try to import the method to another package. Here is the bit that works fine. ------------- #the .r file for package bar setClass("bar",representation("numeric")) if(!isGeneric("print")) {setGeneric("print",useAsDefault=print)} setMethod("print",signature(x="bar"), print.bar <- function(x,...) { print("print method for bar") print(x@.Data,...) } ) if(!isGeneric("barprint")) {setGeneric("barprint",useAsDefault=print)} setMethod("barprint",signature(x="bar"), printBar <- function(x,...) { print("barprint method for bar") print(x@.Data,...) } ) #the NAMESPACE file for package bar import(methods) exportMethods(barprint,print) exportClasses("bar") #then in R:> require(barpkg)Loading required package: barpkg [1] TRUE> x <- new("bar",99) > print(x)[1] "print method for bar" [1] 99> barprint(x)[1] "barprint method for bar" [1] 99 Fine. Here is the bit that I have not figured out. ------------- #the .r file for package waz wazbar <- function(x) { barprint(new("bar",x)) } #the NAMESPACE file for package waz import(methods,barpkg) importMethodsFrom(barpkg) importClassesFrom(barpkg) export(wazbar) #then in R> require(wazpkg)Loading required package: wazpkg [1] TRUE> wazbar(99)Error in .setMethodsForDispatch(f, fdef, resetMlist) : Internal error: did not get a valid generic function object for function "print" Error in print("barprint method for bar") : S language method selection got an error when called from internal dispatch for function "print" end of R bit --------------------------- The problem goes away if I don't set print as an S4 generic in bar. Can anyone help - maybe an error is obvious? As a bit of background, I am package maintainer for its (Irregular Time-Series), and have been obliged to put it in a namespace or suffer a significant performance penalty (about 6x slower). In the package I make S3 generics (plot, print, summary etc) S4 generic in this package, and so far have not got into trouble for doing so. However, I have now got stuck - possibly I have not seen the right documentation (I refer to the newsletter article, and John Chambers' correspondence on R-devel early September). - Giles platform i386-pc-mingw32 arch i386 os mingw32 system i386, mingw32 status major 1 minor 8.1 year 2003 month 11 day 21 language R Rcmd install --doc="none" barpkg ********************************************************************** This is a commercial communication from Commerzbank AG.\ \ T...{{dropped}}
On Thu, 8 Jan 2004, Heywood, Giles wrote:> I have encountered an issue which I have been unable to resolve, involving > an S3 generic (print) being declared S4 generic in a package, and the methodI believe you should not be doing that. The S4 generic for displaying objects is show() and not print(). This matters because auto-printing will use show() rather than print().> being exported. This all works fine - the problem occurs when I try to > import the method to another package.The other thing I noticed is that you have `import(methods)'. That is dangerous, as loading the methods namespace without attaching the package is known to have problems. (Take a look at how package mle does this.) One reason it is dangerous is the following: R_DEFAULT_PACKAGES=NULL R> loadedNamespaces()[1] "base"> .isMethodsDispatchOn()[1] FALSE> loadNamespace("methods")<environment: namespace:methods>> .isMethodsDispatchOn()[1] TRUE> loadedNamespaces()[1] "base" "methods"> library(MASS) > detach("package:MASS")[1] TRUE> .isMethodsDispatchOn()[1] FALSE so if you only load the methods namespace, any call to detach() switches off methods dispatch! That is not the only problem which has been noted. -- 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
Thanks for the tips so far. I have modified the example so that (a) I do not define an S4 method for print [I use summary instead, which gets similar treatment in mle as far as I can see] (b) I do not do use the 'import(methods)' directive [I previously did this because John Chambers explicitly and as point number 1 stated that this was required, in his email dated 6th September - actually I seem to get the same results either way] Nevertheless I get the same behaviour when trying to access a generic method defined in one package [barpkg in my example] and imported into a second package [wazpkg in my example]. If I require() the package I get the behaviour I expect. - Giles #the first bit which is fine------------------ #the .R file for package barpkg setClass("bar",representation("numeric")) setMethod("summary",signature(object="bar"), function(object,...) { print("summary method for bar") summary(object@.Data,...) } ) setGeneric("barprint",useAsDefault=print) setMethod("barprint",signature(x="bar"), function(x,...) { print("barprint method for bar") print(x@.Data,...) } ) #the NAMESPACE file for package barpkg exportMethods(barprint,summary) exportClasses("bar") #in R> require(barpkg)Loading required package: barpkg [1] TRUE> x <- new("bar",1:5) > summary(x)[1] "summary method for bar" Min. 1st Qu. Median Mean 3rd Qu. Max. 1 2 3 3 4 5> barprint(x)[1] "barprint method for bar" [1] 1 2 3 4 5>#now the bit which is has been puzzling to me ------------ #the .R file for package wazpkg wazsummary <- function(x) { summary(new("bar",x)) } wazbarprint <- function(x) { barprint(new("bar",x)) } #the NAMESPACE file for package wazpkg import(barpkg) importMethodsFrom(barpkg) importClassesFrom(barpkg) export(wazsummary,wazbarprint) #in R> require(wazpkg)Loading required package: wazpkg [1] TRUE> wazbarprint(1:5)[1] "barprint method for bar" [1] 1 2 3 4 5> wazsummary(1:5)[1] "summary method for bar" Error in .setMethodsForDispatch(f, fdef, resetMlist) : Internal error: did not get a valid generic function object for function "summary" Error in summary(object@.Data, ...) : S language method selection got an error when called from internal dispatch for function "summary">#HOWEVER... -----------------------> require(barpkg)Loading required package: barpkg [1] TRUE> require(wazpkg)[1] TRUE> wazbarprint(1:5)[1] "barprint method for bar" [1] 1 2 3 4 5> wazsummary(1:5)[1] "summary method for bar" Min. 1st Qu. Median Mean 3rd Qu. Max. 1 2 3 3 4 5 ----------------------------- platform i386-pc-mingw32 arch i386 os mingw32 system i386, mingw32 status major 1 minor 8.1 year 2003 month 11 day 21 language R I use the following: Rcmd install --doc="none" --save wazpkg ********************************************************************** This is a commercial communication from Commerzbank AG.\ \ T...{{dropped}}
You're caught in a subtle "gotcha" with the combination of things you're doing. We're trying to sort out some of the interactions among namespace & methods at the moment, so there may be a nicer solution in the future. Meanwhile, I can tell you the problem and suggest various work-arounds. The basic problem is that by importing barpkg, rather than requiring it, the generic version of "print" is not seen from the recursive call to print inside the S4 method for class "bar". (It's possible this is just a simple bug, but the thread of environments is a bit tricky at this point.) Here's a dump (using options(error=recover)) of your example (NameSpace4==wazpkg, NameSpace3==barpkg) R> library(NameSpace4) R> wazbar(99) Error in .setMethodsForDispatch(f, fdef, resetMlist) : Internal error: did not get a valid generic function object for function "print" Enter a frame number, or 0 to exit 1:wazbar(99) 2:barprint(new("bar", x)) 3:barprint(new("bar", x)) 4:print("barprint method for bar") 5:MethodsListSelect("print", <environment>, structure(list(), methods structure( 6:.setMethodsForDispatch(f, fdef, resetMlist) Selection: 5 Called from: eval(expr, envir, enclos) Browse[1]> find("print") [1] "package:base" So only the S3 version of print on base is seen at this juncture. Hence, crash. This leads to the first work-around: require(barpkg) (e.g., in a .onLoad function for wazpkg) R> require(NameSpace3) Loading required package: NameSpace3 [1] TRUE R> wazbar(99) [1] "barprint method for bar" [1] 99 (because the S4 generic for print is now in the search path). Other probable workarounds (haven't tried them out): - force S4 generics for print, etc. in the wazbar package as well. - don't make S3 generics on base into S4 generics. John "Heywood, Giles" wrote:> > I have encountered an issue which I have been unable to resolve, involving > an S3 generic (print) being declared S4 generic in a package, and the method > being exported. This all works fine - the problem occurs when I try to > import the method to another package. > > Here is the bit that works fine. ------------- > > #the .r file for package bar > > setClass("bar",representation("numeric")) > > if(!isGeneric("print")) {setGeneric("print",useAsDefault=print)} > setMethod("print",signature(x="bar"), > print.bar <- function(x,...) > { > print("print method for bar") > print(x@.Data,...) > } > ) > > if(!isGeneric("barprint")) {setGeneric("barprint",useAsDefault=print)} > setMethod("barprint",signature(x="bar"), > printBar <- function(x,...) > { > print("barprint method for bar") > print(x@.Data,...) > } > ) > > #the NAMESPACE file for package bar > > import(methods) > exportMethods(barprint,print) > exportClasses("bar") > > #then in R: > > > require(barpkg) > Loading required package: barpkg > [1] TRUE > > x <- new("bar",99) > > print(x) > [1] "print method for bar" > [1] 99 > > barprint(x) > [1] "barprint method for bar" > [1] 99 > > Fine. > > Here is the bit that I have not figured out. ------------- > > #the .r file for package waz > > wazbar <- function(x) > { > barprint(new("bar",x)) > } > > #the NAMESPACE file for package waz > > import(methods,barpkg) > importMethodsFrom(barpkg) > importClassesFrom(barpkg) > export(wazbar) > > #then in R > > > require(wazpkg) > Loading required package: wazpkg > [1] TRUE > > wazbar(99) > Error in .setMethodsForDispatch(f, fdef, resetMlist) : > Internal error: did not get a valid generic function object for > function "print" > Error in print("barprint method for bar") : > S language method selection got an error when called from internal > dispatch for function "print" > > end of R bit --------------------------- > > The problem goes away if I don't set print as an S4 generic in bar. > > Can anyone help - maybe an error is obvious? > > As a bit of background, I am package maintainer for its (Irregular > Time-Series), and have been obliged to put it in a namespace or suffer a > significant performance penalty (about 6x slower). In the package I make S3 > generics (plot, print, summary etc) S4 generic in this package, and so far > have not got into trouble for doing so. However, I have now got stuck - > possibly I have not seen the right documentation (I refer to the newsletter > article, and John Chambers' correspondence on R-devel early September). > > - Giles > > platform i386-pc-mingw32 > arch i386 > os mingw32 > system i386, mingw32 > status > major 1 > minor 8.1 > year 2003 > month 11 > day 21 > language R > > Rcmd install --doc="none" barpkg > > ********************************************************************** > This is a commercial communication from Commerzbank AG.\ \ T...{{dropped}} > > ______________________________________________ > R-devel@stat.math.ethz.ch mailing list > https://www.stat.math.ethz.ch/mailman/listinfo/r-devel-- John M. Chambers jmc@bell-labs.com Bell Labs, Lucent Technologies office: (908)582-2681 700 Mountain Avenue, Room 2C-282 fax: (908)582-3340 Murray Hill, NJ 07974 web: http://www.cs.bell-labs.com/~jmc