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

Wacek Kusnierczyk Waclaw.Marcin.Kusnierczyk at idi.ntnu.no
Sat Jun 6 01:49:51 CEST 2009


Martin Morgan wrote:

[...]

>
>> 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.
>   

broken?  in which sense?  do you want to say that it is essential, in an
oo system, to provide a default for each parameter in a
constructor/initializer for the respective class not to be broken? 

>   
>> 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.
>   

yes, i've visited this issue it in one of my earlier examples posted
here.  to me, the fact that you can clone an instance of a class without
the class's constructor/initializer being called (and without using
low-level memory copy operations) is a candidate to be considered a flaw
in the language.  the fact that it breaks the simple instance-counting
pattern (or any similar pattern) is a problem with the language, not the
pattern.

in c++, for example, you can obtain a copy of the representation of an
object, but not without a constructor being called at some point --
either before the copy operation or during it (where the copy
constructor is called):

class Foo {
private:
    static int count;
    int id;
public:
    Foo() { id = ++count; }
    Foo(const Foo& foo) { id = ++count; } };

Foo foo;  // foo.id is 1
Foo bar = foo; // bar.id is 2
Foo yee(bar); // yee.id is 3
Foo daa; // daa.id is 4
Foo.daa = foo; // daa.id is 1


i find the r way, where you can create a copy of an instance without the
object system being involved, potentially confusing for users.


>   
>> 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!) 

fair?  what's fair here?  that just creating a subclass involves
instantiation of the superclass?  makes little sense to me.

> 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. 

but you're talking classes here;  is coercing a *class* to another
*class* implying instantiation?  makes little sense to me. 

> 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.
>   

i consider this a flaw in the object system.  if subclass validation
goes on at the instance level, why couldn't it be postponed until the
user actually creates a new instance?  otherwise, why couldn't it be
done without creating two dummy instances just for the purpose of
validation?



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

well, i see i can define a coerce on my own, and that's fine, but (a)
what does it have to do with setClass, and (b) it does not relate to the
issue of cloning an instance without the class noticing it has a new kid. 


btw, what i see trying your example is:

> showMethods(coerce, class='b', includeDef=TRUE)
Function: coerce (package methods)
from="B", to="A"
function (from, to = "A", strict = TRUE)
from



>

why the difference?  (and why the empty space?)


vQ




More information about the R-help mailing list