[R] S4: Initialization method called during setClass??

Martin Morgan mtmorgan at fhcrc.org
Sat Jun 6 00:55:33 CEST 2009


Wacek Kusnierczyk <Waclaw.Marcin.Kusnierczyk at idi.ntnu.no> writes:

> Martin Morgan wrote:
>> Hi Vitalie --
>>
>> Vitalie S. wrote:
>>   
>>> Dear UseRs,
>>>
>>> A simple class inheritance example:
>>>
>>>     
>>>> setClass("test",representation(a="numeric"))
>>>> setMethod("initialize","test",
>>>>       
>>>           function(.Object,x,...){
>>>               print("Initialization!!!")
>>>               callNextMethod(.Object,a=x,...)
>>>           })
>>>
>>>     
>>>> new("test",x=23)
>>>>       
>>> [1] "Initialization!!!"
>>> An object of class "test"
>>> Slot "a":
>>> [1] 23
>>>     
>>
>> the implicit contract is that the initialize method is written so that
>> new("test") works. This contract comes up at several points during class
>> definition and instantiation. You've identified one of those points.
>>
>>   
>>>> setClass("test2",contains="test",representation(b="integer"))
>>>>       
>>> [1] "Initialization!!!"
>>> Error in .nextMethod(.Object, a = x, ...) : argument "x" is missing,
>>> with no default
>>>     
>>
>> I'm not sure of the details, but part of the class definition is a
>> coercion method, and in defining this new() is called, without
>> arguments, on the contained classes.
>>   
>
> it sounds approximately ok that defining a subclass fails if its
> initalizer does not provide a value required by the initializer of the
> superclass.  pardon me my ignorance, but here's an obvious question: 
> what if i *do* want to extend a class that has an initializer with an
> argument without a default?  (it does not seem to be a particularly
> extravagant idea, does it?)  i can't define the subclass with setClass,
> because it fails, as above, due to a violation of the contract.  but i

I'm speaking as a user, so my understanding is not meant to be
definitive. I'd say the class with the intializer with an argument
without a default is broken, and you should not want to extend it.

> can't define an appropriate initializer for the subclass that would
> fulfil the contract before i define the subclass itself.  deadlock?


> there is another quirk here, or -- in case the above is not a quirk --
> there is a quirk here.  imagine i want to implement a class that counts
> its instances as they are created, assigning to each a unique identifier

remembering that R has copy-on-change semantics that are only
approximately adhered to (e.g., some copying even without change),
this objective would not likely be useful, e.g., it would not be a
good identifier to know that you were dealing with the 'same'
instance, and it would not be the way you'd want to track references
for garbage collection or other clean-up, for instance.

> from a contiguous sequence of integers, starting at 1 (this doesn't seem
> to be a particularly extravagant idea either):
>
>     setClass('foo', representation(id='integer'))
>     setMethod('initialize', 'foo', local({
>         id=0L
>         function(.Object, ...) {
>            id <<- id+1L
>            .Object at id = id
>            return(.Object) } }))
>
>     foos = replicate(3, new('foo'))
>     sapply(foos, slot, 'id')
>     # 1 2 3
>
>     setClass('bar', contains='foo', representation(name='character'))
>     setMethod('initialize', 'bar', function(.Object, name='bar', ...) {
>        .Object at name = name
>        callNextMethod() })
>     bars = replicate(3, new('bar'))
>     sapply(bars, slot, 'id')
>     # 6 7 8
>
> what??  why on earth creating a subclass *calls* (twice!) the
> superclass's initializer?  is there no other way for checking the

once when the superclass is instantiated (fair enough!) and once when
the validity of the subclass is checked -- the way that valildity
checking works is that subclass is validated according to the subclass
validity method, then the subclass is coerced to the superclass, and
the superclass is checked for validity. The user can define the coerce
method, but the default, for class hierarchies where it is
appropriate, involves a call to new(), and hence to initialize and
validObject.

> setClass("A")
[1] "A"
> setClass("B", contains="A", representation(y="numeric"))
[1] "B"
> b <- as(new("B"), "A")
> showMethods(coerce, class="B", includeDef=TRUE)
Function: coerce (package methods)
from="B", to="A"
function (from, to = "A", strict = TRUE) 
if (strict) {
    value <- new("A")
    for (what in "x") slot(value, what) <- slot(from, what)
    value
} else from

Martin
-- 
Martin Morgan
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




More information about the R-help mailing list