From jmc at research.bell-labs.com  Wed Jul  9 15:07:08 2003
From: jmc at research.bell-labs.com (John Chambers)
Date: Wed Jul  9 20:07:47 2003
Subject: [Rd] Packages, generics, S3 and S4
References: <8CBAA121CEB4D5118CB200508BB2BBEF5403DE@xmx8lonib.lonib.commerzbank.com>
Message-ID: <3F0C59CC.CA35C47A@research.bell-labs.com>

"Heywood, Giles" wrote:
> 
> My question has two parts.
> 
> The first is with regard to the frame or environment in which generic
> functions are defined in packages.  It seems as though they are defined
> (i.e. exist as objects) in frame 1, even when defined in a package.

(Frame 1 is an S-Plus concept; presumably you mean the global
environment, the first element in the search path.)

It seems likely you are not using the "saved image" option in the
INSTALL command, which you should use if your package has S4 classes or
methods.

The simple solution is to have a file called "install.R" in your main
package directory (not in the R/ subdirectory).  For most packages, the
file can be empty.  See the online documentation for INSTALL (but ignore
the comment about having require(methods) in the install.R file; this is
out of date since the methods package is normally included by default
now).

Standard calls to setClass, setMethod, etc. will then save the
definitions in an image file that is loaded when the package is
attached.  You need this, otherwise the definitions (currently) go to
the global environment.  That part will be fixed, but you want to use a
saved image anyway, since otherwise the call to library() for the
package will be much slower.

> 
> The following is a short example:
> 
> setClass("track",representation(x="numeric",y="numeric"))
> plotTrack <- function(x,y,...) plot(x@x,x@y,xlab="",ylab="Value",...)
> setGeneric("plotT",def=function(x,y,...) standardGeneric("plotT"))
> setMethod("plotT",signature(x="track",y="missing"),plotTrack)
> 
> This which works with my 'examples', as follows:
> 
> x <- new("track",x=1:10,y=rnorm(10))
> plotT(x)
> 
> The above also passes Rcmd CHECK with the following warnings, which I
> think are not related to my main question:
> 
> Undocumented code objects: "plotTrack"
> Objects with usage in documentation object 'track' but missing from code:
> "plotT"
> 
> Slightly more worrying, I get the following:
> 
> * checking examples ... ERROR
> Running examples failed.
> 
> Ignoring this (only for the time being), I now do 'make pkg-track',
> and encounter no errors.  Loading the package, my 'examples' work fine.
> Returning to the ERROR, it is clear how this has come about.
> 
> ls(.GlobalEnv)
> [1] "plotT"
> 
> So the genericFunction object plotT resides in frame 1  i.e. .GlobalEnv.
> It gets deleted when cleanEx(env=.GlobalEnv) does its job in Rcmd CHECK.
> 
> The other object defined in this package, plotTrack, is in frame 2:
> 
> ls(2)
> [1] "plotTrack"
> 
> I have tried unsuccessfully to put the genericFunction object plotT into
> frame 2, using the 'where' argument in setGeneric.  To cut a long story
> short, I can put it anywhere _except_ frame 2.
> 
> Now it seems to me that I am barking up the wrong tree, but I don't know
> how to proceed.  Any guidance will be gratefully received.
> 
> The second part of my question is this.  I clearly want to define a plot
> method (not naming it plotT)for the 'track' class, which indeed is what
> is described in the 'Green Book' p43.  However the 'Green Book' is largely
> unencumbered by S3 methods AFAIK.  Venables & Ripley (2000) addresses the
> issue of defining an S4 generic on the same name as an S3 generic on p108.
> 
> setMethod("plot",signature(x="fungi",y="missing"),plot.fungi)
> 
> This clearly works, but I am not clear whether the definition of an S4
> generic
> 'on top of' i.e. with the same name 'plot' as an S3 generic (as in the
> example
> above) is generally regarded as bad practice, or is quite OK.  If it is
> done,
> is the above a suitable template, or should the 'def' argument be used?  

Generally, an S3 "generic" function (i.e., a function that calls
UseMethod()) is not much different from an ordinary function with no S3
methods, so far as defining S4 methods is concerned.

Either way

  setGeneric("plot")

creates a new generic function and makes the current function the
default method.  A call to setMethod() where there is no current S4
generic function for this name does the setGeneric call for you.

The call to setGeneric with a `def' argument is usually needed only when
there is no function of the same name and/or you do not want an existing
function to be called as the default.

John

> I
> know that the above _works_, I am more looking for guidance on what is
> regarded as 'good practice' and will not lead to too many problems as the
> S3->S4 migration proceeds.  Any indication of the planned S3->S4 migration
> path
> and timetable would be a welcome bonus.
> 
> I realise that the second question has been aired before in different
> guises,
> but I regret to say I still do not know the answer.
> 
> I am using NT, and R1.7.1, for the above examples.
> 
> Regards
> 
> Giles Heywood
> Portfolio & Risk Advisory Group
> Commerzbank Securities
> 
> tel      + 44 20 7653 7009
> fax      + 44 20 7562 5347
> mobile + 44 7973 266343
> mailto:giles.heywood@commerzbankib.com
> 60 Gracechurch Street, London EC3V 0HR, U.K.
> http://www.cbksec.com/rsh/portfolio&risk.html
> 
> **********************************************************************
> 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


[Rd] Packages, generics, S3 and S4
John Chambers