[R] inheritence in S4

Martin Morgan mtmorgan at fhcrc.org
Wed Mar 5 20:43:38 CET 2008


cgenolin at u-paris10.fr writes:

> Well well well...

You're partly misunderstanding...

> To summarize : let assume that A is a class (slot x) and C is a class
> containing A (A and slot y) - as(c,"A") calls new("A"). So new("A")
> HAS TO works, you can not decide to forbid empty object (unless you
> define setAs("C","A") ?)

new("A") has to work (return a valid object), but you can still create
arbitrary objects with a prototype (provided the prototype is
consistent with your validity function) and / or with initialize
methods (which do not have any named arguments, other than .Object,
without default values). Creating valid objects seems like a good
idea!

> - In addition, any test that you would like to set in initialize or
>   validity have to first check is some field are empty (because
>   if(object at x >0)' will fail if x=numerical(0))

The validity and initialize methods have to be written in a way
consistent with valid objects -- if you want your object to contain
zero-length vectors, then the validity test has to accommodate that
(e.g., if (length(object at x)==0 || all(object at x>0)) {}). If your
initialize method is supposed to return a valid object, then you'd
better construct one! An initialize method on "A" that expected an
argument xValue whose default was 0 might be written as

setMethod("A", "initialize", function(.Object, ..., xValue=0) {
    callNextMethod(.Object, ..., x=xValue)
})

For this simple case you could create the object with a suitable
prototype and not have an initialize method at all

setClass("A", representation(x="numeric"),
    prototype=prototype(x=0))

> - When you call new("C"), the neither new("A") nor intialize("A") are
>   called. (!!!!)

new("A") is not called (why would it be?). If you have an initialize
method on "A" then it will be called. The problem you experienced
before was that your initialize method for "A" REQUIRED additional
arguments.

> So, all the security test you write in initialize "A", you have to
> rewrite them on "C" ?

That is not correct; you do not have to duplicate code to construct an
object of class C.

> I start to undestand why not that much people use S4...
>
> Christophe
>
>> cgenolin at u-paris10.fr writes:
>>
>>> Hi Martin, thanks for your answer
>>>
>>>> But a couple
>>>> of other quick points. I would have written
>>>>
>>>> setMethod("initialize", "A",
>>>>          function(.Object, ..., xValue=numeric(0)){
>>>>              callNextMethod(.Object, ..., x=xValue)
>>>>          })
>>>>
>>>
>>> I am not that much familiar with S3... In our way of writing this
>>> method, 'initialize' for 'A' will call the next method for A, which is
>>> initialise' for 'numeric', is that right ?
>>
>> from below,
>>
>>>>> setClass("A", representation(x="numeric"))
>>
>> The 'next' method refers to arguments in the signature of the generic,
>> i.e., the 'next' method relevant to .Object. For "A", the next method
>> is the default "initialize" method, which will use all named arguments
>> to fill the slots of .Object (and perhaps call validObject, among
>> other things). You can see the code with
>>
>>> showMethods("initialize", classes="ANY", includeDef=TRUE)
>>
>> S3 is not relevant here.
>>
>>>> And finally, the position of 'xValue' and 'yValue' means that
>>>> the arugment has to be named, e.g., new("B", yValue=12). This seems a
>>>> little awkward at first, but seems like a best practice
>>>
>>> I agree with you. But I do not like the use of ... , it lets us to
>>> make many mistake like in :
>>>
>>> print(3.5165,digitts=2)
>>>
>>> There is a typo in digitts, but since print works with ... , R does
>>> not detect the mistake.
>>> So I agree with the importance of naming argument, I always do it but
>>> without 'forcing' it
>>
>> If this were "initialize", and you had provided an invalid named
>> argument, the default method would have failed because there is no
>> slot of that name.
>>
>>>> And finally, in Jim's thread I mention using a constructor. So in
>>>> practice for a case like the above I would not define any initialize
>>>> methods,
>>>
>>> Interesting. Will you still define a validity method or not even ?
>>
>> For a simple case like this there is no extra validity to check beyond
>> that ensured by S4 (e.g., slots of the correct type). If there were
>> constraints, e.g., only positive values, or length one vectors, then
>> I would define a validity function.
>>
>> Martin
>>
>>>
>>> Christophe
>>>
>>>
>>>>
>>>> Christophe Genolini <cgenolin at u-paris10.fr> writes:
>>>>
>>>>> Thanks Martin
>>>>>
>>>>> Well it works except that "as" seems to not like the "initialize"
>>>>> method : the following code (that is the same than yours with some
>>>>> initialize for A B and C) does not compile. It seems that as(c,"A")
>>>>> does not work if we definie a initialize for A...
>>>>>
>>>>> --- 8< --------------
>>>>> setClass("A", representation(x="numeric"))
>>>>> setMethod("initialize","A",function(.Object,value){.Object at x <-
>>>>> value;return(.Object)})
>>>>> a <- new("A",4)
>>>>>
>>>>> setClass("B", representation(y="numeric"))
>>>>> setMethod("initialize","B",function(.Object,value){.Object at y <-
>>>>> value;return(.Object)})
>>>>> b <- new("B",5)
>>>>>
>>>>> setClass("C", contains=c("A", "B"))
>>>>> setMethod("initialize","C",function(.Object,valueA, valueB){
>>>>>     .Object at x <- valueA
>>>>>     .Object at y <- valueB
>>>>>     return(.Object)
>>>>> })
>>>>> c <- new("C",valueA=10,valueB=12)
>>>>>
>>>>> setMethod("show", "A", function(object) cat("A\n"))
>>>>> setMethod("show", "B", function(object) cat("B\n"))
>>>>> setMethod("show", "C", function(object) {
>>>>>     callGeneric(as(object, "A"))
>>>>>     callGeneric(as(object, "B"))
>>>>>     cat("C\n")
>>>>> })
>>>>> c
>>>>> --- 8< --------------------
>>>>>
>>>>> Is there something wrong with the use of 'as' between class and father
>>>>> class?
>>>>>
>>>>> Christophe
>>>>>> Hi Christophe --
>>>>>>
>>>>>> I don't know whether there's a particularly elegant way. This works
>>>>>>
>>>>>> setClass("A", representation(x="numeric"))
>>>>>> setClass("B", representation(y="numeric"))
>>>>>> setClass("C", contains=c("A", "B"))
>>>>>>
>>>>>> setMethod("show", "A", function(object) cat("A\n"))
>>>>>> setMethod("show", "B", function(object) cat("B\n"))
>>>>>> setMethod("show", "C", function(object) {
>>>>>>     callGeneric(as(object, "A"))
>>>>>>     callGeneric(as(object, "B"))
>>>>>>     cat("C\n")
>>>>>> })
>>>>>>
>>>>>>
>>>>>>> new("C")
>>>>>>>
>>>>>> A
>>>>>> B
>>>>>> C
>>>>>>
>>>>>> but obviously involves the developer in making explicit decisions
>>>>>> about method dispatch when there is multiple inheritance.
>>>>>>
>>>>>> Martin
>>>>>>
>>>>>> cgenolin at u-paris10.fr writes:
>>>>>>
>>>>>>
>>>>>>> Hi the list
>>>>>>>
>>>>>>> I define a class A (slot a and b), a class C (slot c and d) and a
>>>>>>> class E that inherit from A and B.
>>>>>>> I define print(A) and print(B). For print(C), I would like to use
>>>>>>> both of them, but I do not see how...
>>>>>>>
>>>>>>> Thanks for your help...
>>>>>>>
>>>>>>> Christophe
>>>>>>>
>>>>>>> ----------------------------------------------------------------
>>>>>>> Ce message a ete envoye par IMP, grace a l'Universite Paris 10 Nanterre
>>>>>>>
>>>>>>> ______________________________________________
>>>>>>> R-help at r-project.org 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.
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>> --
>>>> Martin Morgan
>>>> Computational Biology / Fred Hutchinson Cancer Research Center
>>>> 1100 Fairview Ave. N.
>>>> PO Box 19024 Seattle, WA 98109
>>>>
>>>> Location: Arnold Building M2 B169
>>>> Phone: (206) 667-2793
>>>>
>>>
>>>
>>>
>>> ----------------------------------------------------------------
>>> Ce message a ete envoye par IMP, grace a l'Universite Paris 10 Nanterre
>>>
>>>
>>>
>>
>> --
>> Martin Morgan
>> Computational Biology / Fred Hutchinson Cancer Research Center
>> 1100 Fairview Ave. N.
>> PO Box 19024 Seattle, WA 98109
>>
>> Location: Arnold Building M2 B169
>> Phone: (206) 667-2793
>>
>
>
>
> ----------------------------------------------------------------
> Ce message a ete envoye par IMP, grace a l'Universite Paris 10 Nanterre
>
>
>

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

Location: Arnold Building M2 B169
Phone: (206) 667-2793



More information about the R-help mailing list