From ripley at stats.ox.ac.uk  Tue Jan 24 18:35:30 2012
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Tue, 24 Jan 2012 17:35:30 +0000
Subject: [Rd] factor S4 class is NA when as.character method exists
In-Reply-To: <E66794E69CFDE04D9A70842786030B9325F8A4@PA-MBX03.na.tibco.com>
References: <CAHgH9_F0s+QfZfamfJszfbyt=s7gC=--eOSNFMrkdhGzTZgR-g@mail.gmail.com>
	<6BB22C49-C945-4481-A41F-7E1D29249C10@gmail.com>
	<CAHgH9_GKcJX4Dz1-YQbttOxssK_L8qG089RfAHmnxZT0Yv5gqg@mail.gmail.com>
	<E66794E69CFDE04D9A70842786030B9325F8A4@PA-MBX03.na.tibco.com>
Message-ID: <4F1EEBE2.50408@stats.ox.ac.uk>

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 at .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-bounces at r-project.org [mailto:r-devel-bounces at r-project.org] On Behalf Of Dan Murphy
>> Sent: Monday, January 23, 2012 10:31 PM
>> To: peter dalgaard
>> Cc: r-devel at 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<pdalgd at 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 at .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 at r-project.org mailing list
>>>> 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.mes at cbs.dk  Priv: PDalgd at gmail.com
>>>
>>>
>>
>> 	[[alternative HTML version deleted]]
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel


-- 
Brian D. Ripley,                  ripley at 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



[Rd] factor S4 class is NA when as.character method exists
Prof Brian Ripley