Hi John, John Chambers wrote: > Herve Pages wrote: >> Hi, >> >> It doesn't seem that the dispatching algo is finding my coerce method >> under >> some circumstances. >> Let's say I have 2 classes, A and AA and that AA is just a direct >> extension >> of A with no additional slots: >> >> setClass("A", representation(ii="integer")) >> setClass("AA", contains="A") >> >> I can define a method for coercing my objects to an integer vector with: >> >> setAs("A", "integer", function(from) {cat("I'm the A->integer >> coerce method\n"); [EMAIL PROTECTED]) >> >> and this works as expected when my object is an AA instance: >> >> > aa <- new("AA", ii=sample(10, 5)) >> > as(aa, "integer") >> I'm the A->integer coerce method >> [1] 10 1 6 4 7 >> >> But things don't behave that way anymore if I introduce a direct >> extension of AA: >> >> setClass("OrderedAA", >> contains="AA", >> validity=function(object) >> { >> if (!all(diff([EMAIL PROTECTED]) >= 0)) >> return("slot 'ii' is not ordered") >> TRUE >> } >> ) >> >> and a method for coercing an A object to an OrderedAA object: >> >> setAs("A", "OrderedAA", >> function(from) >> { >> cat("I'm the A->OrderedAA coerce method\n") >> new("OrderedAA", ii=sort([EMAIL PROTECTED])) >> } >> ) >> >> My A->OrderedAA coerce method is not called anymore: >> >> > oaa <- as(aa, "OrderedAA") >> > oaa >> > validObject(oaa) >> Error in validObject(oaa) : >> invalid class "OrderedAA" object: slot 'ii' is not ordered >> >> This looks like a bug to me. >> > Well, obscure perhaps, and not as well documented as it might be. > > Defining a subclass of "AA" creates implicit coerce methods in both > directions. The method from "AA" to its subclass creates a new object > from the subclass, then inserts the inherited slots. > > > selectMethod("coerce", c("AA", "OrderedAA")) > Method Definition: > > function (from, to) > { > obj <- new("OrderedAA") > as(obj, "AA") <- from > obj > }
The problem is that this implicit method doesn't seem to check the validity of the new object. So now my users have an easy way to create broken objects without being told that they are doing something wrong... unless I have redefined a lot of coerce methods in my software (and there can be a lot of them). Unfortunately for me and my project, it looks like most of these "implicit" methods are doing the wrong thing. So if the purpose of having them was to make the developer's life easier, it doesn't work for me. > > Signatures: > from to target "AA" "OrderedAA" > defined "AA" "OrderedAA" > > The situation is made more confusing because these methods are only > explicitly inserted in the coerce() function the first time they're used > (for obvious efficiency reasons). Even worse, after I define my coerce method for A->OrderedAA, and _before_ I try to coerce my first AA object to an OrderedAA object, I get this: > selectMethod("coerce", c("AA", "OrderedAA")) Method Definition: function (from, to = "OrderedAA", strict = TRUE) { cat("I'm the A->OrderedAA coerce method\n") new("OrderedAA", ii = sort([EMAIL PROTECTED])) } Signatures: from to target "AA" "OrderedAA" defined "A" "OrderedAA" which is not reporting the truth (the method that will actually be selected will be the implicit one, not mine). > > Notice that this is a direct method, not an inherited one. It will be > chosen by the method selection from as(). > > So it is true that if you want to override the implicit methods, you > have to do that for each new subclass, presumably when defining the > subclass. > > > setAs("AA", "OrderedAA", > + function(from) > + { > + cat("I'm the A->OrderedAA coerce method\n") > + new("OrderedAA", ii=sor .... [TRUNCATED] > > as(aa, "OrderedAA") > I'm the A->OrderedAA coerce method > An object of class "OrderedAA" > Slot "ii": > [1] 4 5 7 8 10 > > It's possible to argue that an inherited, explicitly defined method, as > in your case, is worth more than a direct, implicitly defined method. It's definitely worth more than a direct, implicitly defined method that produces invalid objects ;-) Anyway I can see why it can be nice (and save some efforts to the developer) to have a coercion mechanism that works out-of-the-box, but I'm wondering whether this is that useful to have implicit coerce methods in _both_ directions. It seems to me that, most of the times, the parent-to-child direction will do the wrong thing, because, generally speaking, you need some extra information (the extra slots) to coerce from the parent class to the child class. Thanks for the clarification! H. > But whether this would be true in all applications is not obvious. > > But that the documentation needs to spell this out--no question. Thanks > for bringing it up. > > John > > >> Thanks, >> H. >> >> ______________________________________________ >> R-devel@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/r-devel >> >> > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel