[Bioc-devel] Class and Inheritance problem

Martin Morgan mtmorgan at fhcrc.org
Fri Sep 21 22:31:38 CEST 2007

After seeing the error, I do

> traceback()

and get

33: isVersioned(object)
32: validityMethod(as(object, superClass))
31: identical(x, TRUE)
30: anyStrings(validityMethod(as(object, superClass)))
29: validObject(.Object)

and groan. callNextMethod eventually leads to the default initialize
method, which constructs an object by filling in slots. The default
method then checks the validity of the object. It does this by
coercing the object from it's actual class through its super-classes,
with (in validObject)

  as(object, superClass)

ExpressionSet extends several classes, the first of which is
"Versioned". There is no coerce method from ACMECalc to Versioned, so
the methods package creates one. We can view it after the error with:

> getMethod("coerce", c("ACMECalc", "Versioned"))

which starts

> getMethod("coerce", c("ACMECalc", "Versioned"))
Method Definition:

function (from, strict = TRUE) 
if (strict) {
    from <- {
        value <- new("ACME")
        for (what in c("assayData", "phenoData", "featureData", 
        "experimentData", "annotation", ".__classVersion__")) slot(value, 
            what) <- slot(from, what)

and you can see the naked call to ACME.

>From a pragmatic perspective, this means that 'new' must be able to be
called with no arguments, and return a valid object. You could define
coerce methods from your class up the chain, but this would be

Since 'new' has to work with no additional arguments, it undermines
the utility of direct calls to 'new' as an interface to construct
objects. This has partly directed me toward favoring constructors
ACMECalc(...) and viewing 'new' as a strictly 'low-level' interface to
the class, much like '@' or 'slot'.

Hope that helps, and that it's not too incorrect.


Sean Davis <sdavis2 at mail.nih.gov> writes:

> I am trying to make what I thought was a simple class inheritance
> structure, but I am running into problems.  The attached script shows
> the problem.  Basically, I have a class ACMECalc that inherits from ACME
> that, in turn, inherits from ExpressionSet.  I would like to allow users
> to call new() on these two new classes with either a set featureData
> argument or the two arguments Position and Chromosome, from which I will
> construct the featureData.  This works fine for the ACME class, but
> calling the initialize method for ACMECalc generates TWO calls to the
> ACME initialize method (it appears to me), the second of which does not
> include the necessary arguments.  I do not understand where the second
> call to the ACME initialize method is coming from, so I'm finding it
> difficult to fix the problem.  I know I am missing an important point in
> how I am doing things, but I just can't see it.  If any one can spare a
> few minutes to run the attached script and look things over, it is
> supposed to be a bare-bones example to illustrate the problem.
> Thanks,
> Sean
> require(Biobase)
> setClass("ACME",
>          contains="ExpressionSet")
> setClass("ACMECalc",
>          representation(windowsize="integer",
>                         threshold="numeric"),
>          prototype=list(windowsize=integer(),
>            threshold=numeric()),
>          contains="ACME")
> setMethod("initialize",signature(.Object="ACME"),
>           function(.Object,
>                    Chromosome,
>                    Position,
>                    featureData=as(data.frame(Chromosome=Chromosome,Position=Position),"AnnotatedDataFrame"),
>                    ...) {
>             print('ACMEInit')
>             print(match.call())
>             if (missing(featureData)) {
>               if (missing(Chromosome) || missing(Position)) {
>                 stop("One of featureData or Chromosome and Position must be specified")
>               }
>               featureData=as(data.frame(Chromosome=Chromosome,Position=Position),"AnnotatedDataFrame")
>             }
>             .Object <- callNextMethod(.Object,
>                                       featureData=featureData,
>                            ...)
>             .Object <- .Object[order(pData(featureData(.Object))$Chromosome,pData(featureData(.Object))$Position),]
>             return(.Object)
>           })
> setMethod("initialize",signature(.Object="ACMECalc"),
>           function(.Object,
>                    Chromosome,
>                    Position,
>                    featureData=as(data.frame(Chromosome=Chromosome,Position=Position),"AnnotatedDataFrame"),
>                    windowsize,
>                    threshold,
>                    ...) {
>             print("ACMECalcInit")
>             print(match.call())
>             .Object <- callNextMethod(.Object,featureData=featureData,...)
>             .Object at windowsize=as.integer(windowsize)
>             .Object at threshold=threshold
>             return(.Object)
>           })
> ###########
> ## Test things
> ###########
> chrom = c(1,2,3,4)
> position=c(5,6,7,8)
> exp1=matrix(1:16,nr=4)
> acme=new("ACME",Chromosome=chrom,Position=position,exprs=exp1)
> acmec=new("ACMECalc",Chromosome=chrom,Position=position,windowsize=1000,threshold=100,exprs=exp1)
> _______________________________________________
> Bioc-devel at stat.math.ethz.ch mailing list
> https://stat.ethz.ch/mailman/listinfo/bioc-devel

Martin Morgan
Bioconductor / Computational Biology

More information about the Bioc-devel mailing list