From jfox at mcmaster.ca  Sat Dec 11 04:58:15 2004
From: jfox at mcmaster.ca (John Fox)
Date: Sat Dec 11 04:58:22 2004
Subject: [Rd] RE: [R] Testing for S4 objects
In-Reply-To: <61842888041130064036da550b@mail.gmail.com>
Message-ID: <20041211035814.KHYJ1836.tomts16-srv.bellnexxia.net@JohnDesktop8300>

Dear r-devel list members,

I'm moving this question to r-devel because it seems thornier than I
originally thought.

I've already mentioned (on r-help) that the approach that John Chambers
suggested (below) fails for objects of class "by":

> x <- rnorm(100)
> y <- sample(2, 100, replace=TRUE)
> res <- by(x, y, mean)
> res
INDICES: 1
[1] -0.03429679
------------------------------------------------------------ 
INDICES: 2
[1] -0.1273790
> class(res)
[1] "by"
> isS4object <- function(object)(length(attr(object, "class"))==1 &&
+     !is.null(getClass(class(object))))
> isS4object(res)
Error in getClass(class(object)) : "by" is not a defined class
> 

I tried to fix that, but I've now discovered more general problems; e.g.:

> mod <- lm(y ~ x)
> class(mod)
[1] "lm"
> isS4object(mod)
[1] TRUE
> class(summary(mod))
[1] "summary.lm"
> isS4object(summary(mod))
Error in getClass(class(object)) : "summary.lm" is not a defined class
> 

I've reverted to a modified version of my original proposal:

> isS4object <- function(object) {
+     !(length(object) == 1 && class(object) == "character") &&
length(slotNames(object)) != 0
+     }
> isS4object(res)
[1] FALSE
> isS4object(mod)
[1] FALSE
> isS4object(summary(mod))
[1] FALSE
> # example from ?mle
> x <- 0:10
> y <- c(26, 17, 13, 12, 20, 5, 9, 8, 5, 4, 8)
> ll <- function(ymax=15, xhalf=6)
+     -sum(stats::dpois(y, lambda=ymax/(1+x/xhalf), log=TRUE))
> fit <- mle(ll)
Warning message: 
NaNs produced in: dpois(x, lambda, log) 
> isS4object(fit)
[1] TRUE
> isS4object("mle")
[1] FALSE
> 

All this is with R 2.0.1 under Windows NT.

Comments would be appreciated.

John

--------------------------------
John Fox
Department of Sociology
McMaster University
Hamilton, Ontario
Canada L8S 4M4
905-525-9140x23604
http://socserv.mcmaster.ca/jfox 
-------------------------------- 

> -----Original Message-----
> From: John Chambers [mailto:johnmchambers@gmail.com] 
> Sent: Tuesday, November 30, 2004 9:40 AM
> To: John Fox
> Cc: Martin Maechler; r-help@stat.math.ethz.ch
> Subject: Re: [R] Testing for S4 objects
> 
> Let me suggest a different test, because slotNames was 
> written to work differently when given a string or a class 
> definition.  With your definition,
> 
> R> x <- "classRepresentation"
> R> isS4object(x)
> [1] TRUE
> 
> which I assume is not what you wanted.  (Given a single string,
> slotNames() tries to look up the class definition of that name.)
> 
> How about the following?  The logic is that an S4 object must 
> have an actual class attribute of length 1 (that rules out 
> basic data types, where class(x) is a string but there is no 
> actual attribute, and also rules out some S3 objects).  Then 
> if that's true, try to look up the class definition.  If it 
> is non-null, seems like an S4 object.
> 
> R> isS4object <- function(object)(length(attr(object, "class"))==1 &&
> +     !is.null(getClass(class(object))))
> R> isS4object(x)
> [1] FALSE
> R> isS4object(getClass(class(x)))
> [1] TRUE
> 
> This definition seems to work, at least on the examples I 
> could think of right away.  Notice though, that some classes, 
> such as "ts", that have been around for a long while are 
> nevertheless legitimate S4 classes, so:
> 
> R> t1 = ts(1:12)
> R> isS4object(t1)
> [1] TRUE
> 
> (this applies to either version of isS4object).
> 
> There are a couple of details, more appropriate for the r-devel list. 
> Seems  a good candidate for a function to add to R.
> 
> 
> On Sat, 27 Nov 2004 17:48:30 -0500, John Fox <jfox@mcmaster.ca> wrote:
> > Dear Martin,
> > 
> > As it turns out, the test that I proposed (i.e., testing for NULL 
> > slotNames) sometimes fails. For example:
> > 
> > > library(car)
> > > data(Prestige)
> > > sum <- summary(lm(prestige ~ income + education, data=Prestige))
> > > slotNames(sum)
> > character(0)
> > 
> > The following, however, seems to work (at least as far as I've been 
> > able to
> > ascertain):
> > 
> > isS4object <- function(object) length(slotNames(object)) != 0
> > 
> > I hope that this is a more robust test.
> > 
> > 
> > 
> > John
> > 
> > --------------------------------
> > John Fox
> > Department of Sociology
> > McMaster University
> > Hamilton, Ontario
> > Canada L8S 4M4
> > 905-525-9140x23604
> > http://socserv.mcmaster.ca/jfox
> > --------------------------------
> > 
> > > -----Original Message-----
> > > From: Martin Maechler [mailto:maechler@stat.math.ethz.ch]
> > > Sent: Friday, November 26, 2004 3:18 AM
> > > To: John Fox
> > > Cc: r-help@stat.math.ethz.ch
> > > Subject: Re: [R] Testing for S4 objects
> > >
> > > >>>>> "JohnF" == John Fox <jfox@mcmaster.ca>
> > > >>>>>     on Thu, 25 Nov 2004 22:28:50 -0500 writes:
> > >
> > >     JohnF> Dear r-help list members, Is there a way to test
> > >     JohnF> whether an object is an S4 object? The best that I've
> > >     JohnF> been able to come up with is
> > >
> > >     JohnF>    isS4object <- function(object)
> > > !(is.null(slotNames(object)))
> > >
> > > you can drop one pair of "(..)" to give
> > >
> > >   isS4object <- function(object) !is.null(slotNames(object))
> > >
> > >
> > >     JohnF> which assumes that an S4 object has at least one
> > >     JohnF> slot. I think this is safe, but perhaps I'm missing
> > >     JohnF> something.
> > >
> > > The question is a very good one -- that I have posed to R-core a 
> > > while ago myself.
> > >
> > > Inside  utils:::str.default  {which doesn't show the many 
> commments 
> > > in the *source* of str.default()}, I have wanted a way that even 
> > > works when the 'methods' package is not attached and use the more 
> > > obscure
> > >
> > >     #NOT yet:if(has.class <- !is.null(cl <- class(object)))
> > >     if(has.class <- !is.null(cl <- attr(object, "class")))#
> > > S3 or S4 class
> > >       S4 <- !is.null(attr(cl, "package"))## <<<'kludge' FIXME!
> > >       ##or length(methods::getSlots(cl)) > 0
> > >
> > > For the time being, I'd keep your function, but I don't 
> think we'd 
> > > guarantee that it will remain the appropriate test in all 
> future.  
> > > But till then many things will have happened (if not all of them 
> > > ;-).
> > >
> > > Martin Maechler, ETH Zurich
> > >
> > 
> > ______________________________________________
> > R-help@stat.math.ethz.ch mailing list
> > https://stat.ethz.ch/mailman/listinfo/r-help
> > PLEASE do read the posting guide! 
> > http://www.R-project.org/posting-guide.html
> >


[Rd] RE: [R] Testing for S4 objects
John Fox