[R] S4: Initialization method called during setClass??
Wacek Kusnierczyk
Waclaw.Marcin.Kusnierczyk at idi.ntnu.no
Fri Jun 5 23:17:43 CEST 2009
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
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
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
contract without actually calling the initializer, as if an instance
(two!) was created? suppose one creates a package defining a hierarchy
of classes with something like 'foo' at the top, and a user of the
package loads it and creates a new -- the first -- instance which
suddenly has 17 as the id -- just imagine the curses.
pardon me for the usual harshness, but this is seems irrational, plain
and simple. i can imagine that this is a well-documented behaviour
(even if that's only in fine print), but the motivation...?
btw.,
sapply(foos, `@`, 'id')
# Error in lapply(X, FUN, ...) :
# no slot of name "..." for this object of class "foo"
even though
`@`(foos[[1]], 'id')
# 1
`slot`(foos[[1]], 'id')
# 1
and sapply works fine with slot. what's wrong here?
deeply confused,
vQ
More information about the R-help
mailing list