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 <[email protected]> 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 <[email protected]>
>> wrote:
>>
>>>>>>>> Martin Maechler <[email protected]>
>>>>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes:
>>>
>>>>>>>> John Chambers <[email protected]>
>>>>>>>> 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 <[email protected]>
>>>>> wrote:
>>>
>>>>>>>>>>> Martin Maechler <[email protected]>
>>>>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>>>
>>>>>>>>>>> John Chambers <[email protected]>
>>>>>>>>>>> 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 <[email protected]> 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")`?
>>>>>>>>>
>>>>>>>>> ______________________________________________
>>>>>>>>> [email protected] mailing list
>>>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>>
>>>>>>>> ______________________________________________
>>>>>>>> [email protected] mailing list
>>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>>
>>>>>>> ______________________________________________
>>>>>>> [email protected] mailing list
>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>
>> [[alternative HTML version deleted]]
>>
>> _______________________________________________
>> [email protected] 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: [email protected]
> Phone: (206) 667-5791
> Fax: (206) 667-1319
>
> ______________________________________________
> [email protected] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
[[alternative HTML version deleted]]
______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel