Extending a group of S4 classes by setClassUnion ?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Extending a group of S4 classes by setClassUnion ?

Alexander
Hi,
I would like to create some S4 classes as follows

setClass("Father",representation(name="character"))
setClass("Son1",contains="Father",representation(par="numeric"))
setClass("Son2",contains="Father",representation(par="logical"))

Son1<-new("Son1")
Son1@name<-"Son1"
Son1@par<-3

Son2<-new("Son2")
Son2@name<-"Son2"
Son2@par<-TRUE

setGeneric("get.par",function(object){standardGeneric ("get.par")})
setMethod("get.par","Son1",function(object){return(object@par+3)})
setMethod("get.par","Son2",function(object){return(!object@par)})

get.par(Son1)
get.par(Son2)

So far, so good. I would like now, to create a new class, which "extends"/"contains" the subclasses of Father by some additional slots.
Is there any clean and simple possibility to inherite also the corresponding function get.par ?

setClass("Extension",representation(person="Father",text="character"))
Ext<-new("Extension")
Ext@text<-"new try"
Ext@person<-Son1
get.par(Ext)
get.par(Ext@person)

Of course, "get.par(Ext)" returns an error. Is there any possibility to tell R, that if now function exists for a Class, to transform the object to a class, for which the function exists ? (I know, it is not very clear what I am writing, but I am doing my best). I don't want to rewrite every method for  "Extension" like

setMethod("get.par","Extension",function(object){get.par(object@person)})

Is there any simpler solution by steClassUnion, setAs, setIs .... ?

Thanks a lot in advance

Alexander
Reply | Threaded
Open this post in threaded view
|

Re: Extending a group of S4 classes by setClassUnion ?

Martin Morgan
Hi Alexander --

On 03/15/2012 07:57 AM, Alexander wrote:

> Hi,
> I would like to create some S4 classes as follows
>
> setClass("Father",representation(name="character"))
> setClass("Son1",contains="Father",representation(par="numeric"))
> setClass("Son2",contains="Father",representation(par="logical"))
>
> Son1<-new("Son1")
> Son1@name<-"Son1"
> Son1@par<-3

it's more efficient to call new("Son1", name="Son1", par=3)

> Son2<-new("Son2")
> Son2@name<-"Son2"
> Son2@par<-TRUE
>
> setGeneric("get.par",function(object){standardGeneric ("get.par")})

functions with '.' in their names can be confusing, because it could
represent an S3 generic on 'get', for an S3 object of class 'par'.

> setMethod("get.par","Son1",function(object){return(object@par+3)})
> setMethod("get.par","Son2",function(object){return(!object@par)})
>
> get.par(Son1)
> get.par(Son2)
>
> So far, so good. I would like now, to create a new class, which
> "extends"/"contains" the subclasses of Father by some additional slots.
> Is there any clean and simple possibility to inherite also the corresponding
> function get.par ?
>
> setClass("Extension",representation(person="Father",text="character"))
> Ext<-new("Extension")
> Ext@text<-"new try"
> Ext@person<-Son1
> get.par(Ext)
> get.par(Ext@person)
>
> Of course, "get.par(Ext)" returns an error. Is there any possibility to tell
> R, that if now function exists for a Class, to transform the object to a
> class, for which the function exists ? (I know, it is not very clear what I
> am writing, but I am doing my best). I don't want to rewrite every method
> for  "Extension" like
>
> setMethod("get.par","Extension",function(object){get.par(object@person)})
>
> Is there any simpler solution by steClassUnion, setAs, setIs .... ?

You can provide an explicit relationship

setIs("Extension", "Father",
       coerce=function(from) from@person,
       replace=function(from, value) {
           from@person <- value
           from
       })

and then define a method on 'Father' (since that's what you're asserting
equivalence to)

setMethod("get.par", "Father", function(object) object@name)

and finally have success with

ext <- new("Extension",
            person=new("Son1", name="Son1", par=3),
            text="new try")

 > get.par(ext)
[1] "Son1"

Neat, eh? But it really pays to ask whether the complexity of the class
structure you're creating is appropriate for the solution that you need
to implement -- imagine, for instance, writing a method that dispatches
on two arguments, and as a programmer you need to implement appropriate
methods for the tangle of dispatch that you have created.

Martin

>
> Thanks a lot in advance
>
> Alexander
>
> --
> View this message in context: http://r.789695.n4.nabble.com/Extending-a-group-of-S4-classes-by-setClassUnion-tp4475251p4475251.html
> Sent from the R help mailing list archive at Nabble.com.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.


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

Location: M1-B861
Telephone: 206 667-2793

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Reply | Threaded
Open this post in threaded view
|

Re: Extending a group of S4 classes by setClassUnion ?

Alexander
Hi Martin,
thanks for your quick answer. I didn't know that '.' could be missleading. Is there any standard way to name function for S4 objects? "get","set" etc..?

I saw your example, and I was wondering, why get.par(ext) put out "Son1", and not the same as get.par(new("Son1", name="Son1", par=3))

If I define a function just like setMethod("get.par", "Father", function(object) object@name) , for example

setMethod("get.par", "Father", function(object) object@par)

then it would work, for all objects, which are either Son1 or Son2, but not all object, which are "Father", contains also the variable par

 get.par(new("Father"))

Alexander

Reply | Threaded
Open this post in threaded view
|

Re: Extending a group of S4 classes by setClassUnion ?

Martin Morgan
On 03/15/2012 09:51 AM, Alexander wrote:
> Hi Martin,
> thanks for your quick answer. I didn't know that '.' could be missleading.
> Is there any standard way to name function for S4 objects? "get","set"
> etc..?

Hi Alexander -- it's usually better to include the original email in the
reply, to provide context especially for those joining the thread later.

I think 'get' and 'set' are implicit in the action of the 'getter'
fun(x) and 'setter' fun(x) <- value function. I would have written (I
wouldn't have used par, which is an existing function unrelated to what
you're trying to do).

   setGeneric("parent",
       function(object, ...) standardGeneric("parent'))
   setMethod("parent", "Father", function(object, ...) object@name)

   setGeneric("parent<-",
       function(object, ..., value) standardGeneric("parent<-"))
   setReplaceMethod("parent", c("Father", "Son1"),
       function(object, ..., value)  {
           object@name <- value
           object
       })

and used as

   parent(obj)
   parent(obj) <- son

I realize I'm confused about Father / Son and 'parent' here, maybe you
meant something else by 'par'.


> I saw your example, and I was wondering, why get.par(ext) put out "Son1",
> and not the same as get.par(new("Son1", name="Son1", par=3))

the setIs established a relationship between Extension and Father; you
could have established a relationship between Extension and Son1

   setIs("Extension", "Son1", <...>)

and then you would get your expected result. I have to say that I have
rarely used setIs, so the complexity of inheritance may hold some
surprises, e.g., when there are setIs defined, from Extension to Father,
Son1, and Son2.

Martin

> If I define a function just like setMethod("get.par", "Father",
> function(object) object@name) , for example
>
> setMethod("get.par", "Father", function(object) object@par)
>
> then it would work, for all objects, which are either Son1 or Son2, but not
> all object, which are "Father", contains also the variable par
>
>   get.par(new("Father"))
>
> Alexander
>
>
>
> --
> View this message in context: http://r.789695.n4.nabble.com/Extending-a-group-of-S4-classes-by-setClassUnion-tp4475251p4475650.html
> Sent from the R help mailing list archive at Nabble.com.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.


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

Location: M1-B861
Telephone: 206 667-2793

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
Reply | Threaded
Open this post in threaded view
|

Re: Extending a group of S4 classes by setClassUnion ?

Alexander
Martin Morgan wrote
On 03/15/2012 09:51 AM, Alexander wrote:
> Hi Martin,
> thanks for your quick answer. I didn't know that '.' could be missleading.
> Is there any standard way to name function for S4 objects? "get","set"
> etc..?

Hi Alexander -- it's usually better to include the original email in the
reply, to provide context especially for those joining the thread later.

I think 'get' and 'set' are implicit in the action of the 'getter'
fun(x) and 'setter' fun(x) <- value function. I would have written (I
wouldn't have used par, which is an existing function unrelated to what
you're trying to do).
In fact, I have several getter and setter. For example gettermean and gettervariance are less clear then getter.mean and getter.variance. The names "mean.getter", "variance.getter" have the disadvantage to have getter and setter not in first place... (Ok, these are very minor problems...)
Martin Morgan wrote
   setGeneric("parent",
       function(object, ...) standardGeneric("parent'))
   setMethod("parent", "Father", function(object, ...) object@name)

   setGeneric("parent<-",
       function(object, ..., value) standardGeneric("parent<-"))
   setReplaceMethod("parent", c("Father", "Son1"),
       function(object, ..., value)  {
           object@name <- value
           object
       })

and used as

   parent(obj)
   parent(obj) <- son

I realize I'm confused about Father / Son and 'parent' here, maybe you
meant something else by 'par'.
Yes indeed, "par" means parameter. But you're right, it is to close to parent and very misleading in this example
Martin Morgan wrote
> I saw your example, and I was wondering, why get.par(ext) put out "Son1",
> and not the same as get.par(new("Son1", name="Son1", par=3))

the setIs established a relationship between Extension and Father; you
could have established a relationship between Extension and Son1

   setIs("Extension", "Son1", <...>)

and then you would get your expected result. I have to say that I have
rarely used setIs, so the complexity of inheritance may hold some
surprises, e.g., when there are setIs defined, from Extension to Father,
Son1, and Son2.

Martin

> If I define a function just like setMethod("get.par", "Father",
> function(object) object@name) , for example
>
> setMethod("get.par", "Father", function(object) object@par)
>
> then it would work, for all objects, which are either Son1 or Son2, but not
> all object, which are "Father", contains also the variable par
>
>   get.par(new("Father"))
>
> Alexander
>
>
>
> --
> View this message in context: http://r.789695.n4.nabble.com/Extending-a-group-of-S4-classes-by-setClassUnion-tp4475251p4475650.html
> Sent from the R help mailing list archive at Nabble.com.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.


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

Location: M1-B861
Telephone: 206 667-2793

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
and provide commented, minimal, self-contained, reproducible code.
I rewrote the example and I think if will have to write some setIs methods. Do you know, how this is done? Here is a little example which shows, that the order of initialization for setIs determins the results !!

setClass("Father",representation(name="character"))
setClass("Son1",contains="Father",representation(parameter="numeric"))
setClass("Son2",contains="Father",representation(parameter="logical"))

Son1<-new("Son1",name="Son1",parameter="3")
Son2<-new("Son2",name="Son2",parameter=TRUE)

setGeneric("get.parameter",function(object){standardGeneric ("get.parameter")})
setMethod("get.parameter","Son1",function(object){return(object@parameter+3)})
setMethod("get.parameter","Son2",function(object){return(object@parameter==TRUE)})

get.parameter(Son1)
get.parameter(Son2)

setClass("Extension",representation(person="Father",text="character"))

ext1 <- new("Extension",person=Son1,text="new try")
ext2 <- new("Extension",person=Son2,text="yesyes")

setIs("Extension", "Son1",test=function(from){print("setIsSon1")
                return(class(from@person)=="Son1")
        },
        coerce=function(from) as(from@person,"Son1",strict=FALSE),
        replace=function(from, value) {from@person <- value
                from
        }
)

setIs("Extension", "Son2",test=function(from){print("setIsSon2")
                return(class(from@person)=="Son2")
        },
        coerce=function(from) as(from@person,"Son2",strict=FALSE),
        replace=function(from, value) {from@person <- value
                from
        }
)

get.parameter(ext1) #"setIsSon1", 6 !!!! correct result
get.parameter(ext2)# "setIsSon1", Error in as(object, "Son1", strict = FALSE) : no method or default for coercing "Extension" to "Son1"

If I open a new R Console and I define setIs("Extension", "Son2", ... ) before setIs("Extension", "Son1", ... ) then I get

get.parameter(ext1) # "setIsSon2", Error in as(object, "Son2", strict = FALSE) : no method or default for coercing "Extension" to "Son2"
get.parameter(ext2)#"setIsSon2", TRUE !!! correct result

Alexander