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?
Thanks in advance
Best Regards
Martin
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. Convert the VCorpus objects to S4 objects, or use S3 objects everywhere. Duncan Murdoch
Hi Martin Kober -- 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.5This has the feel of a workaround, but setOldClass(class(a)[1:2]); setIs("Corpus", "list") helps here, first registering c('vCorpus', 'Corpus') as an S3 hierarchy and then defining the relationship between the root of the hierarchy and (the S4 class) 'list'. Martin (Morgan)>> 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? > > > Thanks in advance > Best Regards > Martin > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel