gunter.berton@gene.com
2005-Aug-05 17:07 UTC
[Rd] S4 setClass with prototypes " issues" (PR#8053)
To R-Developers: I wish to report what I believe are inconsistencies between Green Book descriptions and R methods behaviors. I **realize** that R does not guarantee total consistency with the Green Book; therefore I leave it to you to decide whether any of this is a bug, design choice, or a need for additional documentation -- or whether I have simply misread or overlooked existing explanations. If the latter, I apologize for the error, but it was not for a want of effort. The issues all revolve around the setClass('xxx',prototype=...) without any slots construction. All references are to the Green Book. R 2.1.1 (on Windows) 1. Classes so defined (with protype, no slots) are not instantiated as described on the bottom of p.289. In particular, the following example from the book fails:> setClass('sequence',prototype=numeric(3))[1] "sequence"> new('sequence',c(1,51,10))Error in initialize(value, ...) : cannot use object of class "numeric" in new(): class "sequence" does not extend that class 2. I have been unable to find any Help documentation about the proper method to instantiate classes defined by prototypes without slots. Experimentation showed that only one of the two approaches on the bottom of p.289 worked:> setClass('foo',prototype=numeric())[1] "foo"> z<-new('foo')## new() works as it should> zAn object of class "foo" numeric(0) ## But now try this ...> z<-1:3 > is(z,'numeric')[1] TRUE ## Hence, if R followed the book's statement that "For this to work, 'object' must either be suitable as a prototype for 'myClass or belong to a class that can be coerced to 'myClass.'" (Note, I interpret this to mean that either of these conditions are sufficient for either of the approaches shown).> as(z,'foo')Error in as(z, "foo") : no method or default for coercing "integer" to "foo" ## But> class(z)<-'foo' > zAn object of class "foo" [1] 1 2 3 I was unable to find documentation for this behavior in R, assuming that this is not a bug. If it's a bug, it should be fixed, of course; if not, I think the behavior should be documented, perhaps in setClass. 3. Finally, and most disconcertingly, The Green Book says (p.288): "... We do NOT want a 'sequence' object to be interpreted as a numeric vector ... Doing arbitrary arithmetic on the object, for example would be disastrous... The use of prototypes without representations allows the class designer to limit the legal computations on objects made up of numeric data..." As I read this, this should mean that the following should fail, but it doesn't (continuing the above example):> z+1An object of class "foo" [1] 2 3 4 Again, if this is not a bug, I think that this lack of adherence to the Green book should be documented in R. May I say, however, that I wish R had implemented the book's prescription. -- Bert Gunter Genentech Non-Clinical Statistics South San Francisco, CA "The business of the statistician is to catalyze the scientific learning process." - George E. P. Box
Well, let's say R is currently picky when only a prototype is supplied. The following is either a workaround or a revised, fussier requirement for the example mentioned, depending on your interpretation. R> setClass("sequence", representation(.Data="numeric"), prototype=numeric(3)) [1] "sequence" R> xx <- new('sequence',c(1,51,10)) R> xx An object of class ?sequence? [1] 1 51 10 R> is(xx, "numeric") [1] FALSE So far, so good. But there are a couple of catches. The resolution of prototype and representation is currently somewhat of a mess in the R implementation. There's been some discussion of cleaning it up, hopefully moving ahead from the Green Book description to a more coherent definition. So whether eventually one could (or should) omit the representation() part remains to be seen. The other relevant flaw currently is that S4 objects have no special internal representation in R, so there's effectively no way to keep primitive operations from working on them. (The general & notorious example is that xx[] always returns something on an S4 object, even when it shouldn't.) In the current case, the problem is that, in spite of not extending "numeric", low-level arithmetic is still done. R> xx+1 An object of class ?sequence? [1] 2 52 11 Something basic is needed here, in the code for primitives, but so far objections re efficiency have prevented doing anything. Meanwhile, those more interested in getting something done than discussing, would need to implement explicit methods for the new class that either re-interpret or block the primitives that shouldn't happen in the standard way. gunter.berton at gene.com wrote:> To R-Developers: > > I wish to report what I believe are inconsistencies between Green Book > descriptions and R methods behaviors. I **realize** that R does not > guarantee total consistency with the Green Book; therefore I leave it to you > to decide whether any of this is a bug, design choice, or a need for > additional documentation -- or whether I have simply misread or overlooked > existing explanations. If the latter, I apologize for the error, but it was > not for a want of effort. > > The issues all revolve around the setClass('xxx',prototype=...) without any > slots construction. All references are to the Green Book. R 2.1.1 (on > Windows) > > 1. Classes so defined (with protype, no slots) are not instantiated as > described on the bottom of p.289. In particular, the following example from > the book fails: > > >>setClass('sequence',prototype=numeric(3)) > > [1] "sequence" > >>new('sequence',c(1,51,10)) > > Error in initialize(value, ...) : cannot use object of class "numeric" in > new(): class "sequence" does not extend that class > > 2. I have been unable to find any Help documentation about the proper method > to instantiate classes defined by prototypes without slots. Experimentation > showed that only one of the two approaches on the bottom of p.289 worked: > > >>setClass('foo',prototype=numeric()) > > [1] "foo" > >>z<-new('foo') > > ## new() works as it should > >>z > > An object of class "foo" > numeric(0) > > ## But now try this ... > >>z<-1:3 >>is(z,'numeric') > > [1] TRUE > ## Hence, if R followed the book's statement that "For this to work, > 'object' must either be suitable as a prototype for 'myClass or belong to a > class that can be coerced to 'myClass.'" (Note, I interpret this to mean > that either of these conditions are sufficient for either of the approaches > shown). > > >>as(z,'foo') > > Error in as(z, "foo") : no method or default for coercing "integer" to "foo" > > ## But > >>class(z)<-'foo' >>z > > An object of class "foo" > [1] 1 2 3 > > I was unable to find documentation for this behavior in R, assuming that > this is not a bug. If it's a bug, it should be fixed, of course; if not, I > think the behavior should be documented, perhaps in setClass. > > 3. Finally, and most disconcertingly, The Green Book says (p.288): > > "... We do NOT want a 'sequence' object to be interpreted as a numeric > vector ... Doing arbitrary arithmetic on the object, for example would be > disastrous... > > The use of prototypes without representations allows the class designer to > limit the legal computations on objects made up of numeric data..." > > As I read this, this should mean that the following should fail, but it > doesn't (continuing the above example): > > >>z+1 > > An object of class "foo" > [1] 2 3 4 > > Again, if this is not a bug, I think that this lack of adherence to the > Green book should be documented in R. May I say, however, that I wish R had > implemented the book's prescription. > > > -- Bert Gunter > Genentech Non-Clinical Statistics > South San Francisco, CA > > "The business of the statistician is to catalyze the scientific learning > process." - George E. P. Box > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel >