Re: [Rd] S4 group "Math", "getGroupMembers", "genericForPrimitive"

From: John Chambers <jmc_at_research.bell-labs.com>
Date: Thu 01 Jul 2004 - 07:16:58 EST

R is not S4, the system that the green book describes, although we try to be compatible where there is not a serious reason to be different. The behavior of group generics and of the basic functions, such as those in the Math group, differs.

First, functions such as "log", "sin", and their peers are not generic functions by default in R.

Second, defining methods for the group generic does not automatically turn the members of the group into generic functions.

Some comments about the reason for this approach are given below. But the implication is that code wishing to define methods for the group generic needs to ensure that all the relevant group members are set to be generic functions from the group.

We can provide a function that does this in one step (if no problems arise, it will be in the next release). A simple version of it would look like this:

setGroupMembersOn <- function(group) {

    groupFun <- getGeneric(group)
    for(fun in groupFun@groupMembers)

        if(!isGeneric(fun) && !is.primitive(getFunction(fun)))
            setGeneric(fun, group = group)
}             

The actual version will be somewhat more careful, but this should work in the obvious cases.

Calling

   setGroupMembersOn("Math")
either before or after the setMethod() calls, seems to give the desired effect.

End of the practical part. Some comments on this and on the other questions in your mail:

Some of the Math group are primitive functions and some are not. That's why there is inconsistent behavior. It will stay that way unless the R developers decide that consistency is worth the inefficiency of turning the non-primitves into generic functions. (Probably will have to wait until method dispatch can be made more efficient.)

What we can & should do for the next release is to include the explanation in the documentation of group generic functions.

Matthias.Kohl@uni-bayreuth.de wrote:
>
> Hi,
>
> I found the following on Windows 2000/NT
> R Version 1.9.1 (2004-06-21) (also Version 1.9.0):
>
> The S4 group "Math" doesn't work as documented; i.e., "log", "log10",
> "gamma" and "lgamma" are included
> in the documentation but don't work. See example code below.
>
> Moreover, what about 'genericForPrimitive' which is used
> in 'getGeneric'. It seems that this method is not included in
> the R Version 1.9.1 (also 1.9.0). See the example code of
> John Chambers at the end of this email.
>
> Why not add the method 'getGroupMembers' as proposed by John Chambers
> to the methods package?
> (see reply to mail: "Missing 'getGroupMembers()'"
> from Sat May 31 2003 - 15:18:18 EDT)
>
> Thanks for your attention,
> Matthias
>
> ###################################################
> ## Example Code
> ###################################################
> ## Example Code from the "green book"
> setClass("track", representation(x = "numeric", y = "numeric"))
>
> setMethod("Math", "track",
> function(x){ x@y = callGeneric(x@y); x })
>
> tr1 <- new("track", x = 1:3, y = 1:3)
> tr1
>
> ## are documented as belonging to group "Math"
> ## see ?"Math"
> ## but don't work
> log(tr1)
> log10(tr1)
> gamma(tr1)
> lgamma(tr1)
>
> ## are not generic and don't belong to any group!
> is("log", "genericFunction")
> is("log10", "genericFunction")
> is("gamma", "genericFunction")
> is("lgamma", "genericFunction")
> getGroup("log")
> getGroup("log10")
> getGroup("gamma")
> getGroup("lgamma")
>
> ## make this functions generic and add to group "Math"
> ## (only local!)
> setGeneric("log", function(x, base) standardGeneric("log"), group = "Math")
> setGeneric("log10", function(x) standardGeneric("log10"), group = "Math")
> setGeneric("gamma", function(x) standardGeneric("gamma"), group = "Math")
> setGeneric("lgamma", function(x) standardGeneric("lgamma"), group = "Math")
>
> setMethod("Math", "track",
> function(x){ x@y = callGeneric(x@y); x })
>
> ## now works as documented
> log(tr1)
> log10(tr1)
> gamma(tr1)
> lgamma(tr1)
>
> ## By John Chambers:
> ## "... the following code implements what one is
> ## likely to want in most cases." (see reply
> ## to mail: "Missing 'getGroupMembers()'"
> ## from Sat May 31 2003 - 15:18:18 EDT)
> ## Modification of this code
> ## since 'genericForPrimitive' is not defined (?)
> ## although it is called in 'getGeneric'!!!
> getGroups <- function(what = c(getGenerics(), names(.BasicFunsList))) {
> what <- what[what != "is.function"]
> what <- what[what != "is.null"]
> what <- what[what != "is.object"]
> g <-unlist(sapply(what,
> function(x){
> f <- getGeneric(x)
> if(is(f, "genericFunction"))f@group else NULL
> }))
> split(names(g), g)
> }
> getGroupMembers <- function(group, whatGenerics) {
> groups <- if(missing(whatGenerics)) getGroups()
> else getGroups(whatGenerics)
> elNamed(groups, group)
> }
>
> ______________________________________________
> 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

______________________________________________
R-devel@stat.math.ethz.ch mailing list
https://www.stat.math.ethz.ch/mailman/listinfo/r-devel
Received on Thu Jul 01 07:20:21 2004

This archive was generated by hypermail 2.1.8 : Wed 03 Nov 2004 - 22:45:00 EST