From murdoch at stats.uwo.ca  Tue Sep 15 13:42:29 2009
From: murdoch at stats.uwo.ca (Duncan Murdoch)
Date: Tue, 15 Sep 2009 07:42:29 -0400
Subject: [Rd] S3 objects in S4 slots
In-Reply-To: <19119.31708.308427.313593@lynne.math.ethz.ch>
References: <116117690909150300v4a703807se7b08b94c3f1a68d@mail.gmail.com>	<4AAF6BD8.1010002@stats.uwo.ca>
	<19119.31708.308427.313593@lynne.math.ethz.ch>
Message-ID: <4AAF7DA5.5050608@stats.uwo.ca>

On 15/09/2009 7:34 AM, Martin Maechler wrote:
>>>>>> Duncan Murdoch <murdoch at stats.uwo.ca>
>>>>>>     on Tue, 15 Sep 2009 06:26:32 -0400 writes:
> 
>     > Martin Kober wrote:
>     >> Hello,
>     >> 
>     >> I am the maintainer of the stringkernels package and have come across
>     >> a problem with using S3 objects in my S4 classes.
>     >> 
>     >> Specifically, I have an S4 class with a slot that takes a text corpus
>     >> as a list of character vectors. tm (version 0.5) saves corpora as
>     >> lists with a class attribute of c("VCorpus", "Corpus", "list"). I
>     >> don't actually need the class-specific attributes, I only care about
>     >> the list itself.
>     >> 
>     >> Here's a simplified example of my problem:
>     >> 
>     >> 
>     >>> setClass("testclass", representation(slot="list"))
>     >>> 
>     >> [1] "testclass"
>     >> 
>     >>> a = list(a="1", b="2")
>     >>> class(a) = c("VCorpus", "Corpus", "list") # same as corpora in tm v0.5
>     >>> x = new("testclass", slot=a)
>     >>> 
>     >> Error in validObject(.Object) :
>     >> invalid class "testclass" object: 1: invalid object for slot "slot"
>     >> in class "testclass": got class "VCorpus", should be or extend class
>     >> "list"
>     >> invalid class "testclass" object: 2: invalid object for slot "slot" in
>     >> class "testclass": got class "Corpus", should be or extend class
>     >> "list"
>     >> invalid class "testclass" object: 3: invalid object for slot "slot" in
>     >> class "testclass": got class "list", should be or extend class "list"
>     >> 
>     >> The last line is a bit confusing here (``got class "list", should be
>     >> or extend class "list"''). There's an even more confusing error
>     >> message when I try to assign the slot later on:
>     >> 
>     >> 
>     >>> y = new("testclass")
>     >>> y at slot = a
>     >>> 
>     >> Error in checkSlotAssignment(object, name, value) :
>     >> c("assignment of an object of class \"VCorpus\" is not valid for
>     >> slot \"slot\" in an object of class \"testclass\"; is(value, \"list\")
>     >> is not TRUE", "assignment of an object of class \"Corpus\" is not
>     >> valid for slot \"slot\" in an object of class \"testclass\"; is(value,
>     >> \"list\") is not TRUE", "assignment of an object of class \"list\" is
>     >> not valid for slot \"slot\" in an object of class \"testclass\";
>     >> is(value, \"list\") is not TRUE")
>     >> 
>     >> The last part of the message claims that ``is(value, "list") is not
>     >> TRUE'', but is(a, "list") is certainly TRUE. (??)
>     >> 
>     >> On a side note, it does work when "list" is the first entry in class().
>     >> 
>     >> 
>     >> I tried to use setOldClass, but seemingly using list is not possible
>     >> because it does not extend oldClass, or I didn't find out how to do
>     >> it:
>     >> 
>     >>> setOldClass(c("VCorpus", "Corpus", "list"))
>     >>> 
>     >> Error in setOldClass(c("VCorpus", "Corpus", "list")) :
>     >> inconsistent old-style class information for "list"; the class is
>     >> defined but does not extend "oldClass"
>     >> 
>     >> 
>     >> Intuitively I would have thought that, because the underlying data is
>     >> of type list, it would "fit" into an object slot requiring a list,
>     >> irrespective of S3 class attributes. The only thing I can think of is
>     >> a manual solution removing the class attribute.
>     >> 
>     >> Is there a way to define lists with S3 class attributes such that they
>     >> are accepted as lists in S4 object slots? Or any other ways to solve
>     >> this?
>     >> 
> 
>     > A possible workaround is to store unclass(a) in that slot, rather than 
>     > a.  You won't be able to use the VCorpus or Corpus methods on it, but it 
>     > sounds as though you don't want to.
> 
>     > I would say checkSlotAssignment should be using some variation on 
>     > inherits(), rather than checking for an exact class match, but probably 
>     > the real message is that you shouldn't mix S3 and S4 systems.
> 
> I don't think so.
> Recent releases of R have had big improvements (instrumented by
> John Chambers) in order to make exactly this (S3 classed objects as
> slots of S4 objects) possible !!

Shouldn't an object that inherits from "list" be allowed to occupy a 
slot that wants a list?

Duncan Murdoch


> 
>     >   Convert  the VCorpus objects to S4 objects, or use S3 objects everywhere.
> 
> Well, no, at least not at all according to what I think has been the
> intentions of the recent years' changes of making S3 objects
> better fit into the S4 frame work.
> 
> Martin Maechler



[Rd] S3 objects in S4 slots
Duncan Murdoch