Question: Confusion over inconsistencies with showMethods('Rle') when loaded via GenomicRanges
0
6.8 years ago by
Peter Hickey460
Walter and Eliza Hall Institute of Medical Research, Melbourne, Australia
Peter Hickey460 wrote:
genomicranges • 1.6k views
modified 6.8 years ago by Steve Lianoglou12k • written 6.8 years ago by Peter Hickey460
0
6.8 years ago by
Denali
Steve Lianoglou12k wrote:
Hi Pete, On Wed, Jan 30, 2013 at 7:17 PM, <hickey at="" wehi.edu.au=""> wrote: > Hi Steve, > > Thanks for your explanation. I'm just learning about the S4 class and > methods so I suspected I'd missed something. I ran your example on my > machine and it returned the same output. > > I've now found the real problem in my code but don't understand why is > causing inheritance problems for Rle. Basically, there's a line in my class > definitions to define a class union, namely: setClassUnion('vectorOrNULL', > c("vector", "NULL"). Depending on whether that line is included before I try > to construct the GRanges object determines whether the object is > successfully created. Can anyone please explain this to me? [snip] > ## But this version does not work as intended > ## Firstly, start a fresh R session >> library(GenomicRanges) [snip] >> setClassUnion("vectorOrNULL", c("vector", "NULL")) ## This line is the >> culprit >> out <- list(chr = rep('chr21', 10), 1:10, start = 1:10, end = 2:11) >> showMethods('Rle') > Function: Rle (package IRanges) > values="missing", lengths="missing" > values="vectorORfactor", lengths="integer" > values="vectorORfactor", lengths="missing" > values="vectorORfactor", lengths="numeric" > >> gr <- GRanges(seqnames = out[['chr']], ranges = IRanges(start = >> out[['start']], end = out[['end']])) > Error in function (classes, fdef, mtable) : > unable to find an inherited method for function ?Rle? for signature > ?"character", "missing"? >> showMethods('Rle') > Function: Rle (package IRanges) > values="missing", lengths="missing" > values="vectorORfactor", lengths="integer" > values="vectorORfactor", lengths="missing" > values="vectorORfactor", lengths="numeric" > > ## Inheritance problems for Rle Interesting ... my guess is because with your new class union, both of these are now TRUE: R> is(c('a', 'b', 'c'), 'vectorORfactor') [1] TRUE R> is(c('a', 'b', 'c'), 'vectorOrNULL') [1] TRUE But it really feels like the class union shouldn't be getting in the way -- I mean, if one then writes an Rle method for c("vectorOrNULL", "missing"), I can imagine what the problem might be, but that's not the case here. Hmmm ... if I were a bit bolder, I'd hazard that this might even be a bug somewhere in some S4 dispatching mojo, but I'm not well-versed-enough in its voodoo to make that claim. I suspect Martin will likely chime in to point out what is the what, here ;-) -steve -- Steve Lianoglou Graduate Student: Computational Systems Biology | Memorial Sloan-Kettering Cancer Center | Weill Medical College of Cornell University Contact Info: http://cbio.mskcc.org/~lianos/contact
On 01/30/2013 06:55 PM, Steve Lianoglou wrote: > Hi Pete, > > On Wed, Jan 30, 2013 at 7:17 PM, <hickey at="" wehi.edu.au=""> wrote: >> Hi Steve, >> >> Thanks for your explanation. I'm just learning about the S4 class and >> methods so I suspected I'd missed something. I ran your example on my >> machine and it returned the same output. >> >> I've now found the real problem in my code but don't understand why is >> causing inheritance problems for Rle. Basically, there's a line in my class >> definitions to define a class union, namely: setClassUnion('vectorOrNULL', >> c("vector", "NULL"). Depending on whether that line is included before I try >> to construct the GRanges object determines whether the object is >> successfully created. Can anyone please explain this to me? > [snip] > >> ## But this version does not work as intended >> ## Firstly, start a fresh R session >>> library(GenomicRanges) > [snip] > >>> setClassUnion("vectorOrNULL", c("vector", "NULL")) ## This line is the >>> culprit >>> out <- list(chr = rep('chr21', 10), 1:10, start = 1:10, end = 2:11) >>> showMethods('Rle') >> Function: Rle (package IRanges) >> values="missing", lengths="missing" >> values="vectorORfactor", lengths="integer" >> values="vectorORfactor", lengths="missing" >> values="vectorORfactor", lengths="numeric" >> >>> gr <- GRanges(seqnames = out[['chr']], ranges = IRanges(start = >>> out[['start']], end = out[['end']])) >> Error in function (classes, fdef, mtable) : >> unable to find an inherited method for function ?Rle? for signature >> ?"character", "missing"? >>> showMethods('Rle') >> Function: Rle (package IRanges) >> values="missing", lengths="missing" >> values="vectorORfactor", lengths="integer" >> values="vectorORfactor", lengths="missing" >> values="vectorORfactor", lengths="numeric" >> >> ## Inheritance problems for Rle > > Interesting ... my guess is because with your new class union, both of > these are now TRUE: > > R> is(c('a', 'b', 'c'), 'vectorORfactor') > [1] TRUE > > R> is(c('a', 'b', 'c'), 'vectorOrNULL') > [1] TRUE > > But it really feels like the class union shouldn't be getting in the > way -- I mean, if one then writes an Rle method for c("vectorOrNULL", > "missing"), I can imagine what the problem might be, but that's not > the case here. > > Hmmm ... if I were a bit bolder, I'd hazard that this might even be a > bug somewhere in some S4 dispatching mojo, but I'm not > well-versed-enough in its voodoo to make that claim. > > I suspect Martin will likely chime in to point out what is the what, here ;-) 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
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}}
Hi Pete, On Thu, Jan 31, 2013 at 3:22 AM, <hickey at="" wehi.edu.au=""> wrote: [snip] > 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 at 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 at model_parameters) == TRUE, whereas, > is.null(in_my_class_modelled at 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. I see what you're trying to do -- and I believe I've done this once or twice before myself (which is to use NULL as a place holder under a later call initializes the slot) ... luckily I somehow I never got kicked by the bug/behavior you found. Perhaps in this case, you can just set your model_parameters slot to numeric, and during the initialization/construction of your object, assign NA_real_ as its slot value, or more simply numeric() (a zero-length numeric vector). In this way, you still have a delimiter that indicates this slot is yet to be initialized w/ a proper variable, but you are still using an object of a numeric class to do so -- no class-union's necessary. Would that work for you? HTH, -steve -- Steve Lianoglou Graduate Student: Computational Systems Biology | Memorial Sloan-Kettering Cancer Center | Weill Medical College of Cornell University Contact Info: http://cbio.mskcc.org/~lianos/contact
Hi Steve, On 31/01/2013, at 11:40 PM, Steve Lianoglou wrote: > Hi Pete, > > On Thu, Jan 31, 2013 at 3:22 AM, <hickey@wehi.edu.au> wrote: > [snip] >> 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. > > I see what you're trying to do -- and I believe I've done this once or > twice before myself (which is to use NULL as a place holder under a > later call initializes the slot) ... luckily I somehow I never got > kicked by the bug/behavior you found. > > Perhaps in this case, you can just set your model_parameters slot to > numeric, and during the initialization/construction of your object, > assign NA_real_ as its slot value, or more simply numeric() (a > zero-length numeric vector). > > In this way, you still have a delimiter that indicates this slot is > yet to be initialized w/ a proper variable, but you are still using an > object of a numeric class to do so -- no class-union's necessary. > > Would that work for you? > > HTH, > -steve > > -- > Steve Lianoglou > Graduate Student: Computational Systems Biology > | Memorial Sloan-Kettering Cancer Center > | Weill Medical College of Cornell University > Contact Info: http://cbio.mskcc.org/~lianos/contact I think that's exactly the road I'll go down for the time being. The less I'm messing about with things I don't well understand, the better :) 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}}
0
6.8 years ago by
Peter Hickey460
Walter and Eliza Hall Institute of Medical Research, Melbourne, Australia
Peter Hickey460 wrote: