Using slot() on object (or "@") and using a nonexistent
slotname returns an error (see example code).
R> setClass("foobar", representation=list(a="numeric"))
[1] "foobar"
R> foobar <- new("foobar", a=5)
R> foobar at a
[1] 5
R> foobar at b
Error: no slot of name "b" for this object of class "foobar"
The details section of manpage has a paragraph that
seems to agree with above:
Unlike attributes, slots are not partially matched,
and asking for (or trying to set) a slot with an
invalid name for that class generates an error.
But then the last paragraph in that same section seems to
suggest otherwise.
Currently the @ extraction operator and slot function
do no checking, neither that object has a formal class
nor that name is a valid slot name for the class. (They
will extract the attribute of the given name if it
exists from any R object.) The replacement forms do
check (at least if check=TRUE).
Are these two paragraphs not in partial conflict with each
other? I had initially expected (my initial bottom-up
quick glance only read last paragraph) to get NULL from
invalid slotname.
This is in reference to writing method that might be
passed an object created by previous version of software,
and new slots were added to class in later revisions.
For such situations, is the norm then to do
"slotNames(obj) %in% <slotname>" prior to accessing any
slotname from extended class?
TIA
R version 2.7.0 Patched (2008-06-04 r45830)
----------------------------------------------------------
SIGSIG -- signature too long (core dumped)
slot(obj, "nosuch") documentation question
3 messages · Paul Roebuck, John Chambers, Martin Morgan
1 day later
Paul Roebuck wrote:
Using slot() on object (or "@") and using a nonexistent
slotname returns an error (see example code).
R> setClass("foobar", representation=list(a="numeric"))
[1] "foobar"
R> foobar <- new("foobar", a=5)
R> foobar at a
[1] 5
R> foobar at b
Error: no slot of name "b" for this object of class "foobar"
The details section of manpage has a paragraph that
seems to agree with above:
Unlike attributes, slots are not partially matched,
and asking for (or trying to set) a slot with an
invalid name for that class generates an error.
But then the last paragraph in that same section seems to
suggest otherwise.
Currently the @ extraction operator and slot function
do no checking, neither that object has a formal class
nor that name is a valid slot name for the class. (They
will extract the attribute of the given name if it
exists from any R object.) The replacement forms do
check (at least if check=TRUE).
Are these two paragraphs not in partial conflict with each
other?
No, but a little more detail in the documentation would have been
helpful. See my previous thread on this list: the methods
documentation is getting a major rewrite at the moment.
What's guaranteed is that foobar at b <- 1 will be disallowed if "b" is
not a valid slot name or the right hand side is not coerceable to the
appropriate class. So as long as nobody cheats, only valid slot names
will be found and not finding a slot of an invalid name generates an error.
However.
For various reasons, slots in R were implemented as attributes, and in
the immediate future seem likely to remain so. And, for now, there is
no guarantee that code has not gone around assigning attributes with
other names.
The access function @ or slot() doesn't go off to the class definition
to check the name, so once such an attribute is inserted, it looks like
a "slot". But you still will get an error assigning a value, because
that computation _does_ check validity. All this is in pursuit of
efficiency, arguing that slot access tends to happen more often than
replacement.
The following extension of your example illustrates:
> setClass("foobar", representation=list(a="numeric"))
[1] "foobar"
> foobar <- new("foobar", a=5)
> foobar at a
[1] 5
> foobar at b
Error: no slot of name "b" for this object of class "foobar"
> attr(foobar, "b") <- 10
> foobar at b
[1] 10
> foobar at b <- 1
Error in checkSlotAssignment(object, name, value) :
"b" is not a slot in class "foobar"
I had initially expected (my initial bottom-up quick glance only read last paragraph) to get NULL from invalid slotname. This is in reference to writing method that might be passed an object created by previous version of software, and new slots were added to class in later revisions. For such situations, is the norm then to do "slotNames(obj) %in% <slotname>" prior to accessing any slotname from extended class?
Dangerous practice. I presume what happens is that objects are saved, then restored after the class has been redefined. Restoring the old object creates an invalid object of the class. You really should follow the restore by "fixing" any out of date objects. It would be nice if R had versioning software that did some of this automatically, although in general it's a tough problem. Perhaps other users who have encountered the problem of revising classes might comment on what their practice is. Managing changing class definitions is an interesting and important topic. John
TIA R version 2.7.0 Patched (2008-06-04 r45830) ---------------------------------------------------------- SIGSIG -- signature too long (core dumped)
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
John Chambers <jmc at r-project.org> writes:
Paul Roebuck wrote:
Using slot() on object (or "@") and using a nonexistent slotname returns an error (see example code).
[snip]
This is in reference to writing method that might be passed an object created by previous version of software, and new slots were added to class in later revisions. For such situations, is the norm then to do "slotNames(obj) %in% <slotname>" prior to accessing any slotname from extended class?
Dangerous practice. I presume what happens is that objects are saved, then restored after the class has been redefined. Restoring the old object creates an invalid object of the class. You really should follow the restore by "fixing" any out of date objects. It would be nice if R had versioning software that did some of this automatically, although in general it's a tough problem. Perhaps other users who have encountered the problem of revising classes might comment on what their practice is. Managing changing class definitions is an interesting and important topic.
The not completely satisfactory solution in the Bioconductor package Biobase is classes Versioned (a 'mix-in' class to provide versioning information and dispatch) and Versions (to represent version strings), plus generics isVersioned, isCurrent, classVersion, classVersion<- for accessing Versioned, and updateObject for providing a common interface to the update operation. Versioned is a class with slot .__classVersion__ that the developer populates with a vector of Version objects. isCurrent is meant to be the main entry point for assessing version, and compares the class version of the object with the class version recorded in the class definition. It also grandfathers in instances that existed before Versioned itself was added to the class by checking that the object has its S4 bit set, and that the instance is actually versioned. The developer is expected to write updateObject methods that know how to update from previous versions to the current version, and callNextMethod to delegate responsibility to inherited methods (including a default that tries to create a new instance by copying slots from the current object into a newly created instance). There are several complexities. isCurrent has to make decisions about the current-ness of slot content (much as validObject does). Inheritance means that only a portion of the class hierarchy might be out-of-date so length(Versions) > 1 is the norm. Methods are not associated with classes, so in a sense and for reproducibility 'isCurrent' might mean that the object was created with the same version of R and relevant packages as are currently in use. updateObject would really like to have a semantic and method dispatch like validObject, where each updateObject method takes responsibility for updating only the portion of the class that the method is responsible for. There are a number of aspects that are unsatisfactory about the implementation. The developer has to manage class version numbering (there's no hashing, say, of the class definition to automatically register a new class; hashing is more complicated than at first sight because components of the class can be out of date), including an awkward way of capturing versions of inherited classes. Out-of-date objects are not detected when loaded, but typically when a method fails (and then the user writes to the bioc mailing list and is told to use updateObject; key methods in Biobase check for class version, but this is too expensive for every operation and many packages outside Biobase make use of Biobase classes without checking version information). Writing updateObject methods is challenging, in part because updateObject uses 'standardGeneric' for dispatch and the developer has to manage both updating the object and dispatching to appropriate 'next' methods.
From the user perspective, updateObject seems to have been quite
successful -- it provides a clean way for the user to solve a problem, once it's been diagnosed. Improvements on an iteration of this might (a) develop a default updateObject method that 'did the right thing' more reliably, much as 'initialize,ANY-method' does. In fact, the current updateObject,ANY-method does seem to be moderately successful at this. (b) generalize the 'validObject' dispatch model and use that to more clearly delineate the responsibilities of updateObject methods (which currently have to be update their part of the object and dispatch to the 'next' method and slots, if appropriate). (c) check object version on load, which would require a change to R itself, or some unique discipline on the part of objects from the package. Martin
John
TIA R version 2.7.0 Patched (2008-06-04 r45830) ---------------------------------------------------------- SIGSIG -- signature too long (core dumped)
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
______________________________________________ R-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel
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