On 31/01/2013, at 5:45 PM, Martin Morgan wrote:

>> [snip]
> 
> Yep, this is a puzzler. Here's what happens in a fresh R session:
> 
>  > setClassUnion("vectorORfactor", c("vector", "factor"))
>  > getClass("numeric")
>  Class "numeric" [package "methods"]
> 
>  No Slots, prototype of class "numeric"
> 
>  Extends:
>  Class "vector", directly
>  Class "vectorORfactor", by class "vector", distance 2
> 
>  Known Subclasses:
>  Class "integer", directly
>  Class "ordered", by class "factor", distance 3
> 
> and then
> 
>  > setClassUnion("vectorOrNULL", c("vector", "NULL"))
>  > getClass("numeric")
>  Class "numeric" [package "methods"]
> 
>  No Slots, prototype of class "numeric"
> 
>  Extends:
>  Class "vector", directly
>  Class "vectorORfactor", by class "vector", distance 2
>  Class "vectorOrNULL", by class "vector", distance 2
> 
>  Known Subclasses:
>  Class "integer", directly
>  Class "ordered", by class "factor", distance 3
> 
> Notice that "numeric" extends our two class unions.
> 
> Now when we're dealing with a package, focusing on the 'Extends:' component
> 
>  library(IRanges)
>  > getClass("numeric")
>  ...
>  Extends:
>  Class "vector", directly
>  Class "atomic", directly
>  Class "vectorORfactor", by class "vector", distance 2
>  > setClassUnion("vectorOrNULL", c("vector", "NULL"))
>  > getClass("numeric")
>  ...
>  Extends:
>  Class "vector", directly
>  Class "vectorOrNULL", by class "vector", distance 2
> 
> so we have replaced rather than amended Extends:. I think the error with method dispatch follows from this -- we end up looking for a method defined on vectorORNULL, and don't find one.
> 
> I think the problem is in methods::assignClassDef, but things get a bit hairy for me; maybe there are class definitions for numeric that are found in IRanges, and in methods, and the latter over-writes the former?
> 
> A work-around seems to be to setClassUnion() before loading IRanges.
> 
> I find class unions pretty weird -- reach in to the class hierarchy and saying no, inheritance works _this_ way and at the same time making things complicated for ourselves because we always have to check whether the slot is a vector or NULL -- I wonder what you're hoping to accomplish with this? I know the pattern is well-established in IRanges...
> 
> Martin
> 
>> 
>> -steve
>> 
> 
> 
> -- 
> 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

Hi Martin and Steve,

Thanks for taking the time to explain this to me. As I said, I'm just learning S4 classes and I think this is a case of me trying to move too fast, too soon :) 

Here's what I'm trying to accomplish with a setClassUnion(). I've based my class on the 'BSseq' class in the 'bsseq' package; partly for didactic purposes (it always helps me to have something to work-off when getting started with a new programming concept) and partly because I'm also dealing with BS-seq data. My reason for using a 'setClassUnion("vectorOrNULL'",  c("vector", "NULL"))' is that for some of the slots the values aren't defined (i.e. they are NULL) when my object is first created; rather they are defined by a subsequent function call.

In pseudo-code it goes something like this:
> library(GenomicRanges)
> setClassUnion("vectorOrNULL'",  c("vector", "NULL"))
> setClass('MyClass", representation(gr = "GRanges", model_parameters = "vectorOrNULL"))
> in <- read_input_file(some_input_file)
> in_gr <- input_file_to_GRanges(in) # Convert 'in' to a GRanges object
> in_my_class <- MyClass(gr = in_gr, model_parameters = NULL) 
## At this point, is.null(in_my_class@model_parameters) == TRUE
## Now, some modelling is done based on 'in_my_class'. 
in_my_class_modelled <- modeling_function(in_my_class) ## This function returns a MyClass object, with the 'model_parameters' slot now filled by a vector of model parameters.
## At this point, is.null(in_my_class@model_parameters) == TRUE, whereas, is.null(in_my_class_modelled@model_parameters) == FALSE

Basically, I'd really like to have the model_parameters in the same MyClass object as the raw data (along with some other things, like sampleName etc.) but these aren't available at the point when the MyClass object is first constructed. The 'modelling_function()' returns a new MyClass object, with the 'gr' slot copied from the input 'in_my_class' and the 'model_parameters' slot filled by a vector rather than a NULL. Incidentally, I believe this is similar to the logic employed by Kasper with the BSseq class in the 'bsseq' package, which uses a GRanges object for the slot used to store the raw data as a GRanges object alongside a 'setClassUnion("matrixOrNULL", c("matrix", "NULL"))' slot for the model parameters, which are NULL when the BSseq object is created and are a matrix in the new BSseq object created by a modelling function ('BSmooth') when applied to the original BSseq object.

I realise this might not be the proper way of doing things; for instance, there is a lot of seemingly redundant copying going on. I'm definitely open to suggestions of better ways of implementing this.

Cheers,
Pete


--------------------------------
Peter Hickey,
PhD Student/Research Assistant,
Bioinformatics Division,
Walter and Eliza Hall Institute of Medical Research,
1G Royal Parade, Parkville, Vic 3052, Australia.
Ph: +613 9345 2324

hickey@wehi.edu.au
http://www.wehi.edu.au


______________________________________________________________________
The information in this email is confidential and intend...{{dropped:8}}

