But my NA issue does not arise from the S3 generic 'unique' alone but from the interaction of that S3 generic with the non-S3 generic 'as.character' (R.methodsS3::isGenericS3.default("as.character") returns FALSE). Here is Bill's code with his S3 as.character foo method replaced by my S4.
> setClass("foo", contains="numeric") [1] "foo" > setMethod("as.character", "foo", function(x) paste("x=", x@.Data)) [1] "as.character" > unique.foo <- function(x, ...) structure(NextMethod("unique"), class=class(x)) > someFoo <- new("foo", c(11, 13, 11, 13, 12)) > str(factor(someFoo)) Factor w/ 3 levels "11","12","13": NA NA NA NA NA I thought I remember reading at some point in the past that package developers were encouraged to implement methods in S4 rather than S3 because ... S3 support would dissipate? I can't remember the details. ... In any event, this example suggests that I should first implement methods in S3 if possible because that approach is more robust, at least as measured by potential S3 pitfalls. I have no problems with that. Thanks for the hints. - Dan On Tue, Jan 24, 2012 at 9:35 AM, Prof Brian Ripley <rip...@stats.ox.ac.uk>wrote: > On 24/01/2012 17:17, William Dunlap wrote: > >> Here is code that does make factor() work on a new >> class like yours. It uses Sv3 methods. >> > > Which is necessary as unique() is an S3 generic in the base namespace, and > creating some other function named 'unique' elsewhere (which is what > setGeneric does) is ineffective. > > > > setClass("foo", contains="numeric") >> [1] "foo" >> > as.character.foo<- function(x) paste("x=",x@.Data,sep="") >> > unique.foo<- function(x, ...) structure(NextMethod("unique")**, >> class=class(x)) >> > someFoo<- new("foo", c(11, 13, 11, 13, 12)) >> > str(factor(someFoo)) >> Factor w/ 3 levels "x=11","x=12",..: 1 3 1 3 2 >> >> It would be nice to have a list of methods that one >> needs to define for a new class in order to make it >> do the "basic" things you expect. >> > > It would be nice to have a list of such things ... I suspect they depend > more heavily on the value of 'you' than the class. > > > Bill Dunlap >> Spotfire, TIBCO Software >> wdunlap tibco.com >> >> -----Original Message----- >>> From: r-devel-boun...@r-project.org [mailto:r-devel-bounces@r-** >>> project.org <r-devel-boun...@r-project.org>] On Behalf Of Dan Murphy >>> Sent: Monday, January 23, 2012 10:31 PM >>> To: peter dalgaard >>> Cc: r-devel@r-project.org >>> Subject: Re: [Rd] factor S4 class is NA when as.character method exists >>> >>> Thank you for your reply, Peter. But that didn't work either. Continuing >>> the example: >>> >>> setGeneric("unique") >>> setMethod("unique", "foo", function(x, incomparables = FALSE, ...){ >>> y<- callNextMethod(x = getDataPart(x), incomparables = >>> incomparables, >>> ...) >>> new("foo", y) >>> }) >>> >>> unique(bar) >>>> >>> An object of class "foo" >>> [1] 12 >>> >>>> factor(bar) >>>> >>> [1]<NA> >>> Levels: 12 >>> >>> Indeed I had tried stepping through the 'factor' call, but perhaps in an >>> unsophisticated manner -- I had copied the body of 'factor' to a local >>> version of the function: >>> >>> myfactor<- function (x = character(), levels, labels = levels, exclude = >>> NA, >>> ordered = is.ordered(x)) >>> { >>> if (is.null(x)) ... >>> etc. >>> >>> And 'myfactor' worked as desired: >>> >>> myfactor(bar) >>>> >>> [1] x= 12 >>> Levels: x= 12 >>> >>> I hypothesized that there might be a deeper interaction of an S4 >>> 'as.character' method with base::factor, but, having exhausted my woeful >>> lack of expertise, I decided to write my original email. >>> >>> Thanks for your consideration. >>> >>> Dan >>> >>> On Mon, Jan 23, 2012 at 8:25 AM, peter dalgaard<pda...@gmail.com> >>> wrote: >>> >>> >>>> On Jan 23, 2012, at 16:07 , Dan Murphy wrote: >>>> >>>> Hello, >>>>> >>>>> 'factor' returns<NA> for my S4 object when the class is given an >>>>> "as.character" method. Here is a minimal example: >>>>> >>>>> setClass("foo", contains="numeric") >>>>>> bar<- new("foo", 12) >>>>>> factor(bar) >>>>>> >>>>> [1] 12 >>>>> Levels: 12 >>>>> >>>>>> setMethod("as.character", "foo", function(x) paste("x=", x@.Data)) >>>>>> >>>>> [1] "as.character" >>>>> >>>>>> as.character(bar) >>>>>> >>>>> [1] "x= 12" >>>>> >>>>>> factor(bar) >>>>>> >>>>> [1]<NA> >>>>> Levels: 12 >>>>> >>>>> I would like to 'aggregate' by my S4 objects, but 'factor' seems to be >>>>> getting in the way. Is there an 'as.character' implementation that >>>>> works >>>>> better for S4 classes? I searched help.search("factor S4 class") and >>>>> help.search("factor S4 as.character") without success. >>>>> >>>> >>>> Single-stepping the factor call would have shown you that the real >>>> problem >>>> is that you don't have a unique() method for your class: >>>> >>>> unique(bar) >>>>> >>>> [1] 12 >>>> >>>> i.e., you are getting the default numeric method, which returns a >>>> numeric >>>> vector, so the levels become as.character(unique(bar)) which is c("12") >>>> and >>>> doesn't match any of the values of as.character(bar). >>>> >>>> So, either provide a unique() method, or use factor(as.character(bar)). >>>> >>>> >>>>> Thank you. >>>>> >>>>> Dan Murphy >>>>> >>>>> [[alternative HTML version deleted]] >>>>> >>>>> ______________________________**________________ >>>>> R-devel@r-project.org mailing list >>>>> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel> >>>>> >>>> >>>> -- >>>> Peter Dalgaard, Professor >>>> Center for Statistics, Copenhagen Business School >>>> Solbjerg Plads 3, 2000 Frederiksberg, Denmark >>>> Phone: (+45)38153501 >>>> Email: pd....@cbs.dk Priv: pda...@gmail.com >>>> >>>> >>>> >>> [[alternative HTML version deleted]] >>> >>> ______________________________**________________ >>> R-devel@r-project.org mailing list >>> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel> >>> >> >> ______________________________**________________ >> R-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/**listinfo/r-devel<https://stat.ethz.ch/mailman/listinfo/r-devel> >> > > > -- > Brian D. Ripley, rip...@stats.ox.ac.uk > Professor of Applied Statistics, > http://www.stats.ox.ac.uk/~**ripley/<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 > [[alternative HTML version deleted]] ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel