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 .obj...@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', ...) { .obj...@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 ______________________________________________ R-help@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.