[Bioc-devel] Extend class definition on attaching a package

Martin Morgan mtmorgan at fhcrc.org
Sat Aug 28 05:32:03 CEST 2010


On 08/27/2010 01:08 PM, Venkatraman Seshan wrote:
> OK.  Can you help me with the following then?
> 
> I want to create a class with two slots, "x" a numeric vector and "y" a
> rectangular array of numeric data which can be a matrix, big.matrix,
> ff_matrix etc.  I want to be agnostic to any of the large data package.  So
> I don't want my package to depend on any of them (since matrix is always
> available). The only methods for the slot y I want are the ability to access
> and replace rows, columns and sub arrays (i.e the usual [ and [<-
> operators).  Can this be done or is it a fools errand?

Hi Venkat --

One could (despite my advice!) use a class union, or relax the class
definition but enforce structure in the validity method (below). I think
you'd end up dispatching 'by-hand' using if (is(slot(object, "m"),
"matrix") ... instead of writing methods (to avoid complaints about
missing class definitions). The oligoClasses package uses ff and matrix
and might be a source of inspiration; Benilton might have some comments
on 'lessons learned' from his experience... I'd still opt for one
representation and go with it, but it's your package!

Martin

setClass("Foo", representation=representation(m="ANY"),
         prototype=prototype(m=matrix(0, 0, 0)))

setValidity("Foo", function(object) {
    msg <- NULL
    cls <- class(slot(object, "m"))
    if (length(cls) != 1 ||
        !cls %in% c("matrix", "big.matrix", "ff_matrix"))
        msg <- "bad matrix type"
    if (is.null(msg)) TRUE else msg
})


> 
> Venkat
> 
> 
> On Fri, Aug 27, 2010 at 12:22 PM, Martin Morgan <mtmorgan at fhcrc.org> wrote:
> 
>> On 08/26/2010 05:58 PM, Venkatraman Seshan wrote:
>>> Thanks Martin.  I was probably making it more complicated than it needed
>> to
>>> be.  I just want to load bigmemory package (if it is installed) and
>> redefine
>>> the classes. I followed your advice and now AllClasses.R is
>>>
>>> setClassUnion("mymatrix", c("mymatrix"))
>>> setClass("mydata", representation(x="numeric", y="cnmatrix"))
>>>
>>> and zzz.R is
>>>
>>> .onLoad <- function(libname, pkgname) {
>>>   bigmem <-
>>> suppressWarnings(suppressPackageStartupMessages(require(bigmemory)))
>>>   if (bigmem) {
>>>     setClassUnion("cnmatrix", c("matrix", "big.matrix"))
>>>     setClass("mydata", representation(x="numeric", y="cnmatrix"))
>>>   }}
>>>
>>> Now it seems to work but I get the following warning message both on R
>> CMD
>>> check and loading the package within R
>>>
>>> Class "big.matrix" is defined (with package slot bigmemory) but no
>> metadata
>>> object found to revise superClass information---not exported?  Making a
>> copy
>>> in package foo
>>>
>>> I assume it is because NAMESPACE doesn't have importClasseFrom(bigmemory,
>>> big.matrix)
>>>
>>> Is there a way I can change the NAMESPACE (in .onLoad or elsewhere)?
>>
>> I guess you're trying to develop a package that has functionality that
>> has code that is conditional on the bigmemory package -- if bigmemory is
>> available then do one thing, otherwise do another. But this is not, in
>> my opinion, a good idea -- your user gets different behavior on Monday
>> versus Wednesday (because they installed bigmemory on Tuesday) and you
>> have two code branches to maintain (which leads to headaches, as
>> evidenced by this thread!). So I think you really just want to
>>
>>  Imports: bigmemmory
>>
>> in your DESCRIPTION file,
>>
>> importClassesFrom(bigmemory, big.matrix)
>>
>> in NAMESPACE
>>
>> and
>>
>> setClassUnion("cnmatrix", c("matrix", "big.matrix"))
>> setClass("mydata",
>>          representation=representation(x="numeric", y="cnmatrix"))
>>
>> in the 'top level' (i.e., not in .onLoad or other function call) of some
>> R/*R file.
>>
>> Actually my stronger advice is that you avoid the setClassUnion --
>> you're really saying that your 'cnmatrix' walks and talks exactly like a
>> matrix and a big.matrix, and vice versa, when really you have no control
>> over what methods are defined for matrix or big.matrix (any package can
>> define methods for these classes) so you have no idea whether the
>> methods are appropriate for cnmatrix. Better in my opinion to implement
>> the interface that is directly relevant to cnmatrix, even if it is often
>> simple delegation to a 'matrix' slot of cnmatrix.
>>
>> Martin
>>
>>
>>>
>>> Thanks again,
>>> Venkat
>>>
>>>
>>> On Thu, Aug 26, 2010 at 7:58 PM, Martin Morgan <mtmorgan at fhcrc.org>
>> wrote:
>>>
>>>> On 08/26/2010 12:58 PM, Venkatraman Seshan wrote:
>>>>> In AllClasses.R I used
>>>>>
>>>>> setClassUnion("cnmatrix", c("matrix"))
>>>>>
>>>>> Sorry for the typo.
>>>>>
>>>>> Venkat
>>>>>
>>>>> On Thu, Aug 26, 2010 at 3:31 PM, Venkatraman Seshan <
>> veseshan at gmail.com
>>>>> wrote:
>>>>>
>>>>>> Can the class definition in package "foo" be changed after the package
>>>> is
>>>>>> attached?  I am trying to do the following.
>>>>>>
>>>>>> The AllClasses.R file has the following class definitions.
>>>>>>
>>>>>> setClassUnion("mymatrix", c("mymatrix"))
>>>>>> setClass("mydata", representation(x="numeric", y="cnmatrix"))
>>>>>>
>>>>>> In zzz.R the .onLoad has the following:
>>>>>>
>>>>>>   setHook(packageEvent("bigmemory", "attach"),
>>>>>>           function(...){
>>>>>>             setIs("big.matrix", "cnmatrix")
>>>>>>             setClass("mydata", representation(x="numeric",
>> y="cnmatrix")
>>>>>>           })
>>>>>>
>>>>>> When I now do R CMD check pkg it is completed but I get a note
>>>>>>
>>>>>> * checking R code for possible problems ... NOTE
>>>>>> Error in setIs("big.matrix", "cnmatrix") :
>>>>>>   cannot create a 'setIs' relation when neither of the classes
>>>>>> ("big.matrix" and "cnmatrix") is local and modifiable in this package
>>>>>>
>>>>>> How do I modify the definition of a class in a package?
>>>>
>>>> Hi Venkat -- not really answering your question, but I don't really
>>>> think you want to do either setClassUnion or setIs -- inheritance is
>>>> difficult enough to understand without adding novel relationships
>>>> between classes. And I don't think you really want to conditionally
>>>> define class relationships on package load either (which I is guess what
>>>> setHook(packageEvent()) accomplishes; I've never seen that before);
>>>> these all sound like you're making trouble for yourself (and users of
>>>> your package) in the future.
>>>>
>>>> But...
>>>>
>>>> .onLoad is run after Import: and Depend: packages have been loaded, and
>>>> before the name space of the package in which .onLoad is defined is
>>>> 'sealed'. I think this means that if you had Import'ed or Depend'ed on
>>>> bigmemory, then a setIs and setClass in .onLoad (not setHook(...)) would
>>>> be successful, just as
>>>>
>>>>> library(bigmemory)
>>>>> setClassUnion("cnmatrix", "matrix")
>>>> [1] "cnmatrix"
>>>>> setIs("big.matrix", "cnmatrix")
>>>>> setClass("mydata", representation(x="numeric", y="cnmatrix"))
>>>> [1] "mydata"
>>>>
>>>> are successful when run in an R session.
>>>>
>>>> So I guess what happens is the 'packageEvent' isn't actually evaluated
>>>> in .onLoad, but afterward, when bigmemory is loaded (by some other code
>>>> in your package? I'm not understanding how R CMD check is detecting the
>>>> error) and your name space has already been sealed (which occurs after
>>>> the .onLoad hook runs) and is therefore not modifiable. Maybe you could
>>>> create an environment in your package
>>>>
>>>>  .secrets <- new.env(parent=emptyenv())
>>>>  setPackageName("MyPackage", .secrets)
>>>>
>>>> and place your class definition there
>>>>
>>>>  setClass("cnmatrix", where=.secrets)
>>>>
>>>> .secrets isn't sealed, so the class definition might still be
>>>> modifiable. I really don't know how this would work, e.g., exporting
>>>> cnmatrix from your package name space, invoking methods, etc., or
>>>> whether it would provide a way to modify the class definition once the
>>>> name space is sealed. My little experiments suggest that you can create
>>>> an instance with
>>>>
>>>>  new(getClassDef("cnmatrix", where=MyPackage:::.secrets))
>>>>
>>>> or by
>>>>
>>>>  attach(MyPackage:::.secrets, name="search")
>>>>  new("MyClass")
>>>>
>>>> and create a setIs relationship, without generating errors or warnings,
>>>> with
>>>>
>>>>  attach(MyPackage:::.secrets, name="secrets")
>>>>  setIs("big.matrix", "cnmatrix", where="secrets")
>>>>  detach("secrets")
>>>>
>>>> but all of this seems like a big hack.
>>>>
>>>> Martin
>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Venkat
>>>>>>
>>>>>> My R.Version()
>>>>>> $platform
>>>>>> [1] "x86_64-pc-linux-gnu"
>>>>>>
>>>>>> $arch
>>>>>> [1] "x86_64"
>>>>>>
>>>>>> $os
>>>>>> [1] "linux-gnu"
>>>>>>
>>>>>> $system
>>>>>> [1] "x86_64, linux-gnu"
>>>>>>
>>>>>> $status
>>>>>> [1] ""
>>>>>>
>>>>>> $major
>>>>>> [1] "2"
>>>>>>
>>>>>> $minor
>>>>>> [1] "11.1"
>>>>>>
>>>>>> $year
>>>>>> [1] "2010"
>>>>>>
>>>>>> $month
>>>>>> [1] "05"
>>>>>>
>>>>>> $day
>>>>>> [1] "31"
>>>>>>
>>>>>> $`svn rev`
>>>>>> [1] "52157"
>>>>>>
>>>>>> $language
>>>>>> [1] "R"
>>>>>>
>>>>>> $version.string
>>>>>> [1] "R version 2.11.1 (2010-05-31)"
>>>>>>
>>>>>>
>>>>>
>>>>>       [[alternative HTML version deleted]]
>>>>>
>>>>> _______________________________________________
>>>>> Bioc-devel at stat.math.ethz.ch mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/bioc-devel
>>>>
>>>>
>>>> --
>>>> Martin Morgan
>>>> Computational Biology / Fred Hutchinson Cancer Research Center
>>>> 1100 Fairview Ave. N.
>>>> PO Box 19024 Seattle, WA 98109
>>>>
>>>> Location: Arnold Building M1 B861
>>>> Phone: (206) 667-2793
>>>>
>>>
>>
>>
>> --
>> Martin Morgan
>> Computational Biology / Fred Hutchinson Cancer Research Center
>> 1100 Fairview Ave. N.
>> PO Box 19024 Seattle, WA 98109
>>
>> Location: Arnold Building M1 B861
>> Phone: (206) 667-2793
>>
> 


-- 
Martin Morgan
Computational Biology / Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N.
PO Box 19024 Seattle, WA 98109

Location: Arnold Building M1 B861
Phone: (206) 667-2793



More information about the Bioc-devel mailing list