[Bioc-devel] prada package and eSet in Biobase

Martin Morgan mtmorgan at fhcrc.org
Thu Apr 13 23:15:24 CEST 2006


Hi Florian --

Florian Hahne <f.hahne at dkfz.de> writes:

> 1.) I prefer to set the validation function already with the class
> definition. Is there a reason I should not do that and use setValidity
> instead?

It would be fine to define the validation function in the
class. Sometimes the validity checking function is useful in other
circumstances, and it would then be less convenient to access and
reuse it.

> 2.) Does it make sense to program the constructor/initialzer in a way
> that one has to give all the items of assayData individualy? Wouldn't
> it be better to accept a predefined assayData object? Or should one
> just do something like this:
>
> obj  <- new("mytestSet")
> ad <- assayDataNew(storage.mode="list",
>                                   exprs = matrix(1:9, ncol=3),
>                                   other = matrix(1:9, ncol=3),
>                                   stuff = matrix(1:9, ncol=3))
> assayData(obj) <- ad

Using specific element names makes expectation about what assayData
should contain clear. It also separates the use of the class from the
implementation details of the way elements are stored.

More technically, as suggested by assayDataNew (rather than "new"),
the AssayData class is a little special. It is a class union of list
and environment. Classes cannot 'contain' environments.

setClass("A", contains="AssayData")
[1] "A"
> new("A")
An object of class "A"
logical(0)
> validObject(new("A"))
Error in validObject(new("A")) : invalid class "A" object: invalid
object for slot ".Data" in class "A": got class "logical", should be
or extend class "AssayData"

For this reason, one cannot instantiate or derive useful classes from
AssayData -- it serves as a predicate to identify objects that can
occupy the assayData slot, and for method dispatch purposes. Other
classes can have useful derived subclasses. So for instance one could
derive a subclass from "AnnotatedDataFrame"

setClass("B", representation(myX="numeric"),contains="AnnotatedDataFrame")

and use that to define a specialized class derived from eSet:

setClass("BSet", representation(phenoData="B"), contains="eSet",
         prototype(phenoData=new("B")))

setMethod("initialize","BSet", function(.Object, ...) {
  callNextMethod()
})

> obj <- new("BSet", phenoData=new("B"))
> 
> obj <- new("BSet", phenoData=new("AnnotatedDataFrame"))
Error in checkSlotAssignment(object, name, value) : 
	assignment of an object of class "AnnotatedDataFrame" is not valid for slot 'phenoData' in an object of class "BSet"; is(value, "B") is not TRUE

In essence, and in contrast to the other slots, the responsibility for
controlling initialization of the assayData slot lies with eSet. 

On a related note, probably a slightly better implementation of
"initialize" for SwirlSet is

setMethod("initialize", "SwirlSet",
          function(.Object,
                   phenoData = new("AnnotatedDataFrame"),
                   experimentData = new("MIAME"),
                   annotation = character(),
                   R = new("matrix"),
                   G = new("matrix"),
                   Rb = new("matrix"),
                   Gb = new("matrix"),
                   ... ) {
            callNextMethod(.Object,
                           phenoData = phenoData,
                           experimentData = experimentData,
                           annotation = annotation,
                           R=R, G=G, Rb=Rb, Gb=Gb,
                           ...)
          })

> 3.) Shouldn't all of eSet's replacement methods call validObject
> before they finish? I always find it a waste of time writing validator
> functions and then by doing a stupid replacement (like the one above)
> create invalid objects without even noticing.

The problem is exactly the one you noted above: it is not unreasonable
to expect that a user (or developer of Biobase) might want to alter an
object in several steps:

myFancyFunction <- function(obj) {
  assayData(obj) <- fancyAssaydData # obj invalid...
  phenoData(obj) <- justAsFancyPhenoData # but now valid
  validObject(obj)
  obj
}

This would not be possible if validity were checked at each
replacement. Probably it would encourage developers to access slots
directly, and this would be very bad when the underlying reprsentation
of the class changed. 

> Hope these questions are not completely stupid but that's what I
> noticed while playing around with the new stuff.

Great questions, and I hope I haven't lied too much in trying to
answer them.

Martin



More information about the Bioc-devel mailing list