Re: coerce() methods. Important to realize that as() does not call selectMethod() in the standard way, but restricts inheritance to the first argument: asMethod <- selectMethod("coerce", sig, optional = TRUE, c(from = TRUE, to = FALSE), fdef = coerceFun, A valid comparison would have to take account of this.
Once the method has been _correctly_ selected, it is stored in the internal table and therefore will be returned by .findMethodInTable without repeating a search. John On Dec 25, 2015, at 11:51 PM, Herv� Pag�s <hpa...@fredhutch.org> wrote: > Or maybe the "right" concept is that "numeric" is a virtual class > with 3 subclasses: "complex", "double", and "integer". Anyway it's > probably too late for implementing the "right" concept so it doesn't > really matter. > > Thanks Martin for offering to fix the as(1L, "numeric") bug. Very > much appreciated. I guess that means fixing the class(x) <- "numeric" > bug on integer vectors: > > > x <- 1L > > class(x) <- "numeric" > > class(x) > [1] "integer" > > My wish for 2016: that selectMethod() always tells the truth. For > example selectMethod("coerce", c("integer", "numeric")) doesn't > in a fresh session, only after you call as(1L, "numeric")). Full > story here: > > https://stat.ethz.ch/pipermail/r-devel/2010-April/057098.html > > Thanks, > H. > > > On 12/19/2015 10:09 AM, John Chambers wrote: >> As I tried to say on Dec. 11, there are two levels of "fix": >> >> 1. The fix to the complaint in the OP's subject heading is to conform to >> the default third argument, strict=TRUE: as(1L, "numeric") == 1.0 >> >> This generates some incompatibilities, as for classes that extend "numeric". >> But still leaves class(1.0) "numeric" and typeof(1.0) "double". >> >> The workaround for class definitions that really need NOT to coerce integers >> to double is to define a class union, say >> setClassUnion("Number", c("numeric", "integer")) >> and use that for the slot. >> >> 2. The "right" concept is arguably that "numeric" is a virtual class with >> two subclasses, "double" and "integer". Given a time machine back to < >> 1998, that would be my choice. But already in the 1998 S4 book, "numeric" >> was equated with "double". >> >> so, there it is, IMO. This is what you get with a successful open-source >> language: Much hassle to do the "right thing" after the fact and the more >> change, the more hassle. >> >> Fix 1. seems to me an actual bug fix, so my inclination would be to go with >> that (on r-devel), advertising that it may change the effective definition >> of some classes. >> >> But I can sympathize with choosing 1, 2 or neither. >> >> John >> >> PS: Until Jan. 4, I may be even poorer at replying than usual, while >> getting the current book off to the publisher. >> >> On Dec 19, 2015, at 3:32 AM, Martin Maechler <maech...@stat.math.ethz.ch> >> wrote: >> >>>>>>>> Martin Maechler <maech...@stat.math.ethz.ch> >>>>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes: >>> >>>>>>>> John Chambers <j...@r-project.org> >>>>>>>> on Fri, 11 Dec 2015 10:11:05 -0800 writes: >>> >>>>> Somehow, the most obvious fixes are always back-incompatible these days. >>>>> The example intrigued me, so I looked into it a bit (should have been >>>>> doing something else, but ....) >>> >>>>> You're right that this is the proverbial thin-edge-of-the-wedge. >>> >>>>> The problem is in setDataPart(), which will be called whenever a class >>>>> extends one of the vector types. >>> >>>>> It does >>>>> as(value, dataClass) >>>>> The key point is that the third argument to as(), strict=TRUE by default. >>>>> So, yes, the change will cause all integer vectors to become double when >>>>> the class extends "numeric". Generally, strict=TRUE makes sense here and >>>>> of course changing THAT would open up yet more incompatibilities. >>> >>>>> For back compatibility, one would have to have some special code in >>>>> setDataPart() for the case of integer/numeric. >>> >>>>> John >>> >>>>> (Historically, the original sin was probably not making a distinction >>>>> between "numeric" as a virtual class and "double" as a type/class.) >>> >>>> Yes, indeed. In the mean time, I've seen more cases where >>>> "the change will cause all integer vectors to become double when the class >>>> extends "numeric". >>>> seems detrimental. >>> >>>> OTOH, I still think we could go in the right direction --- >>>> hopefully along the wishes of bioconductor S4 development, see >>>> Martin Morgan's e-mail: >>> >>>> [This is all S4 - only; should not much affect base R / S3] >>>> Currently, "integer" is a subclass of "numeric" and so the >>>> "integer become double" part seems unwanted to me. >>>> OTOH, it would really make sense to more formally >>>> have the basic subclasses of "numeric" to be "integer" and "double", >>>> and to let as(*, "double") to become different to as(*, "numeric") >>>> [Again, this is just for the S4 classes and as() coercions, *not* e.g. >>>> for as.numeric() / as.double() !] >>> >>>> In the DEPRECATED part of the NEWS for R 2.7.0 (April 2008) we >>>> have had >>> >>>> o The S4 pseudo-classes "single" and double have been removed. >>>> (The S4 class for a REALSXP is "numeric": for back-compatibility >>>> as(x, "double") coerces to "numeric".) >>> >>>> I think the removal of "single" was fine, but in hindsight, >>>> maybe the removal of "double" -- which was partly broken then -- >>>> possibly could rather have been a fixup of "double" along the >>>> following >>> >>>> Current "thought experiment proposal" : >>> >>>> 1) "numeric" := {"integer", "double"} { class - subclasses } >>>> 2) as(1L, "numeric") continues to return 1L .. since integer is >>>> one case of "numeric" >>>> 3) as(1L, "double") newly returns 1.0 {and in fact would be >>>> "equivalent" to as.double(1L)} >>> >>>> After the above change, S4 as(*, "double") would correspond to S3 >>>> as.double >>>> but as(*, "numeric") would continue to differ from >>>> as.numeric(*), the former *not* changing integers to double. >>> >>>> Martin >>> >>> Also note that e.g. >>> >>> class(pi) would return "double" instead of "numeric" >>> >>> and this will break all the bad programming style usages of >>> >>> if(class(x) == "numeric") >>> >>> which I tend to see in gazillions of user and even package codes >>> This bad (aka error prone !) because "correct" usage would be >>> >>> if(inherits(x, "numeric")) >>> >>> and that of course would *not* break after the change above. >>> >>> - - - - >>> >>> A week later, I'm still pretty convinced it would be worth going >>> in the direction proposed above. >>> >>> But I was actually hoping for some encouragement or "mental support"... >>> or then to hear why you think the proposition is not good or not >>> viable ... >>> >>> >>>>> On Dec 11, 2015, at 1:25 AM, Martin Maechler <maech...@stat.math.ethz.ch> >>>>> wrote: >>> >>>>>>>>>>> Martin Maechler <maech...@stat.math.ethz.ch> >>>>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes: >>>>>> >>>>>>>>>>> John Chambers <j...@r-project.org> >>>>>>>>>>> on Mon, 7 Dec 2015 16:05:59 -0800 writes: >>>>>> >>>>>>>> We do need an explicit method here, I think. >>>>>>>> The issue is that as() uses methods for the generic function coerce() >>>>>>>> but cannot use inheritance in the usual way (if it did, you would be >>>>>>>> immediately back with no change, since "integer" inherits from >>>>>>>> "numeric"). >>>>>> >>>>>>>> Copying in the general method for coercing to "numeric" as an explicit >>>>>>>> method for "integer" gives the expected result: >>>>>> >>>>>>>>> setMethod("coerce", c("integer", "numeric"), getMethod("coerce", >>>>>>>>> c("ANY", "numeric"))) >>>>>>>> [1] "coerce" >>>>>>>>> typeof(as(1L, "numeric")) >>>>>>>> [1] "double" >>>>>> >>>>>>>> Seems like a reasonable addition to the code, unless someone sees a >>>>>>>> problem. >>>>>>>> John >>>>>> >>>>>>> I guess that that some package checks (in CRAN + Bioc + ... - >>>>>>> land) will break, >>>>>>> but I still think we should add such a coercion to R. >>>>>> >>>>>>> Martin >>>>>> >>>>>> Hmm... I've tried to add the above to R >>>>>> and do notice that there are consequences that may be larger than >>>>>> anticipated: >>>>>> >>>>>> Here is example code: >>>>>> >>>>>> myN <- setClass("myN", contains="numeric") >>>>>> myNid <- setClass("myNid", contains="numeric", >>>>>> representation(id="character")) >>>>>> NN <- setClass("NN", representation(x="numeric")) >>>>>> >>>>>> (m1 <- myN (1:3)) >>>>>> (m2 <- myNid(1:3, id = "i3")) >>>>>> tools::assertError(NN (1:3))# in all R versions >>>>>> >>>>>> ## # current R | new R >>>>>> ## # -----------|---------- >>>>>> class(getDataPart(m1)) # integer | numeric >>>>>> class(getDataPart(m2)) # integer | numeric >>>>>> >>>>>> >>>>>> In other words, with the above setting, the traditional >>>>>> gentleperson's agreement in S and R, >>>>>> >>>>>> __ "numeric" sometimes conveniently means "integer" or "double" __ >>>>>> >>>>>> will be slightly less often used ... which of course may be a >>>>>> very good thing. >>>>>> >>>>>> However, it breaks strict back compatibility also in cases where >>>>>> the previous behavior may have been preferable: >>>>>> After all integer vectors need only have the space of doubles. >>>>>> >>>>>> Shall we still go ahead and do apply this change to R-devel >>>>>> and then all package others will be willing to update where necessary? >>>>>> >>>>>> As this may affect the many hundreds of bioconductor packages >>>>>> using S4 classes, I am -- exceptionally -- cross posting to the >>>>>> bioc-devel list. >>>>>> >>>>>> Martin Maechler >>>>>> >>>>>> >>>>>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner <bty...@gmail.com> wrote: >>>>>> >>>>>>>>> Perhaps it is not that surprising, given that >>>>>>>>> >>>>>>>> mode(1L) >>>>>>>>> [1] "numeric" >>>>>>>>> >>>>>>>>> and >>>>>>>>> >>>>>>>> is.numeric(1L) >>>>>>>>> [1] TRUE >>>>>>>>> >>>>>>>>> On the other hand, this is curious, to say the least: >>>>>>>>> >>>>>>>> is.double(as(1L, "double")) >>>>>>>>> [1] FALSE >>>>>>>>> >>>>>>>> Here's the surprising behavior: >>>>>>>> >>>>>>>> x <- 1L >>>>>>>> xx <- as(x, "numeric") >>>>>>>> class(xx) >>>>>>>> ## [1] "integer" >>>>>>>> >>>>>>>> It occurs because the call to `as(x, "numeric")` dispatches the coerce >>>>>>>> S4 method for the signature `c("integer", "numeric")`, whose body is >>>>>>>> copied in below. >>>>>>>> >>>>>>>> function (from, to = "numeric", strict = TRUE) >>>>>>>> if (strict) { >>>>>>>> class(from) <- "numeric" >>>>>>>> from >>>>>>>> } else from >>>>>>>> >>>>>>>> This in turn does nothing, even when strict=TRUE, because that >>>>>>>> assignment to class "numeric" has no effect: >>>>>>>> >>>>>>>> x <- 10L >>>>>>>> class(x) <- "numeric" >>>>>>>> class(x) >>>>>>>> [1] "integer" >>>>>>>> >>>>>>>> Is this the desired behavior for `as(x, "numeric")`? >>>>>>>>> >>>>>>>>> ______________________________________________ >>>>>>>>> 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 >>>>>> >>>>>>> ______________________________________________ >>>>>>> R-devel@r-project.org mailing list >>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel >> >> >> [[alternative HTML version deleted]] >> >> _______________________________________________ >> bioc-de...@r-project.org mailing list >> https://stat.ethz.ch/mailman/listinfo/bioc-devel >> > > -- > Herv� Pag�s > > Program in Computational Biology > Division of Public Health Sciences > Fred Hutchinson Cancer Research Center > 1100 Fairview Ave. N, M1-B514 > P.O. Box 19024 > Seattle, WA 98109-1024 > > E-mail: hpa...@fredhutch.org > Phone: (206) 667-5791 > Fax: (206) 667-1319 > > ______________________________________________ > R-devel@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel [[alternative HTML version deleted]]
______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel