

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")`?
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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")`?
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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
On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> John Chambers < [hidden email]>
>>>>> 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
> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel > ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Martin Maechler < [hidden email]>
>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>> John Chambers < [hidden email]>
>>>>> 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 Rdevel
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
biocdevel list.
Martin Maechler
>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel >> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel > ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
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.)
On Dec 11, 2015, at 1:25 AM, Martin Maechler < [hidden email]> wrote:
>>>>>> Martin Maechler < [hidden email]>
>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>
>>>>>> John Chambers < [hidden email]>
>>>>>> 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 Rdevel
> 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
> biocdevel list.
>
> Martin Maechler
>
>
>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


From the Bioconductor side of things, the general feeling is that this is a step in the right direction and worth the broken packages. Martin Morgan
________________________________________
From: Rdevel [ [hidden email]] on behalf of Martin Maechler [ [hidden email]]
Sent: Friday, December 11, 2015 4:25 AM
To: John Chambers; [hidden email]; biocdevel list; Benjamin Tyner
Cc: Martin Maechler
Subject: Re: [Rd] For integer vectors, `as(x, "numeric")` has no effect.
>>>>> Martin Maechler < [hidden email]>
>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>> John Chambers < [hidden email]>
>>>>> 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 Rdevel
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
biocdevel list.
Martin Maechler
>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel >> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel > ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevelThis email message may contain legally privileged and/or confidential information. If you are not the intended recipient(s), or the employee or agent responsible for the delivery of this message to the intended recipient(s), you are hereby notified that any disclosure, copying, distribution, or use of this email message is prohibited. If you have received this message in error, please notify the sender immediately by email and delete this email message from your computer. Thank you.
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> John Chambers < [hidden email]>
>>>>> on Fri, 11 Dec 2015 10:11:05 0800 writes:
> Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
> 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 email:
[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 pseudoclasses "single" and double have been removed.
(The S4 class for a REALSXP is "numeric": for backcompatibility
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
> On Dec 11, 2015, at 1:25 AM, Martin Maechler < [hidden email]> wrote:
>>>>>>> Martin Maechler < [hidden email]>
>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>
>>>>>>> John Chambers < [hidden email]>
>>>>>>> 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 Rdevel
>> 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
>> biocdevel list.
>>
>> Martin Maechler
>>
>>
>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel >>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel >>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Martin Maechler < [hidden email]>
>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes:
>>>>> John Chambers < [hidden email]>
>>>>> on Fri, 11 Dec 2015 10:11:05 0800 writes:
>> Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
>> 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 email:
> [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 pseudoclasses "single" and double have been removed.
> (The S4 class for a REALSXP is "numeric": for backcompatibility
> 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 < [hidden email]> wrote:
>>>>>>>> Martin Maechler < [hidden email]>
>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>
>>>>>>>> John Chambers < [hidden email]>
>>>>>>>> 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 Rdevel
>>> 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
>>> biocdevel list.
>>>
>>> Martin Maechler
>>>
>>>
>>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>>>
>>>>>> ______________________________________________
>>>>>> [hidden email] mailing list
>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel >>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel >>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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 opensource 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 rdevel), 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 < [hidden email]> wrote:
>>>>>> Martin Maechler < [hidden email]>
>>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes:
>
>>>>>> John Chambers < [hidden email]>
>>>>>> on Fri, 11 Dec 2015 10:11:05 0800 writes:
>
>>> Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
>
>>> 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 email:
>
>> [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 pseudoclasses "single" and double have been removed.
>> (The S4 class for a REALSXP is "numeric": for backcompatibility
>> 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 < [hidden email]> wrote:
>
>>>>>>>>> Martin Maechler < [hidden email]>
>>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>
>>>>>>>>> John Chambers < [hidden email]>
>>>>>>>>> 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 Rdevel
>>>> 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
>>>> biocdevel list.
>>>>
>>>> Martin Maechler
>>>>
>>>>
>>>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>>>>
>>>>>>> ______________________________________________
>>>>>>> [hidden email] mailing list
>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>
>>>>>> ______________________________________________
>>>>>> [hidden email] mailing list
>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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/rdevel/2010April/057098.htmlThanks,
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 opensource 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 rdevel), 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 < [hidden email]> wrote:
>
>>>>>>> Martin Maechler < [hidden email]>
>>>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes:
>>
>>>>>>> John Chambers < [hidden email]>
>>>>>>> on Fri, 11 Dec 2015 10:11:05 0800 writes:
>>
>>>> Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
>>
>>>> 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 email:
>>
>>> [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 pseudoclasses "single" and double have been removed.
>>> (The S4 class for a REALSXP is "numeric": for backcompatibility
>>> 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 < [hidden email]> wrote:
>>
>>>>>>>>>> Martin Maechler < [hidden email]>
>>>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>>
>>>>>>>>>> John Chambers < [hidden email]>
>>>>>>>>>> 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 Rdevel
>>>>> 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
>>>>> biocdevel list.
>>>>>
>>>>> Martin Maechler
>>>>>
>>>>>
>>>>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>>>>>
>>>>>>>> ______________________________________________
>>>>>>>> [hidden email] mailing list
>>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>
>>>>>>> ______________________________________________
>>>>>>> [hidden email] mailing list
>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>
>>>>>> ______________________________________________
>>>>>> [hidden email] mailing list
>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>
>
> [[alternative HTML version deleted]]
>
> _______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/biocdevel>

Hervé Pagès
Program in Computational Biology
Division of Public Health Sciences
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N, M1B514
P.O. Box 19024
Seattle, WA 981091024
Email: [hidden email]
Phone: (206) 6675791
Fax: (206) 6671319
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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 < [hidden email]> 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/rdevel/2010April/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 opensource 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 rdevel), 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 < [hidden email]> wrote:
>>
>>>>>>>> Martin Maechler < [hidden email]>
>>>>>>>> on Sat, 12 Dec 2015 10:32:51 +0100 writes:
>>>
>>>>>>>> John Chambers < [hidden email]>
>>>>>>>> on Fri, 11 Dec 2015 10:11:05 0800 writes:
>>>
>>>>> Somehow, the most obvious fixes are always backincompatible 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 thinedgeofthewedge.
>>>
>>>>> 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 email:
>>>
>>>> [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 pseudoclasses "single" and double have been removed.
>>>> (The S4 class for a REALSXP is "numeric": for backcompatibility
>>>> 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 < [hidden email]> wrote:
>>>
>>>>>>>>>>> Martin Maechler < [hidden email]>
>>>>>>>>>>> on Tue, 8 Dec 2015 15:25:21 +0100 writes:
>>>>>>
>>>>>>>>>>> John Chambers < [hidden email]>
>>>>>>>>>>> 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 Rdevel
>>>>>> 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
>>>>>> biocdevel list.
>>>>>>
>>>>>> Martin Maechler
>>>>>>
>>>>>>
>>>>>>>> On Dec 7, 2015, at 3:37 PM, Benjamin Tyner < [hidden email]> 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")`?
>>>>>>>>>
>>>>>>>>> ______________________________________________
>>>>>>>>> [hidden email] mailing list
>>>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>>
>>>>>>>> ______________________________________________
>>>>>>>> [hidden email] mailing list
>>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>>
>>>>>>> ______________________________________________
>>>>>>> [hidden email] mailing list
>>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>
>>
>> [[alternative HTML version deleted]]
>>
>> _______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/biocdevel>>
>
> 
> Herv� Pag�s
>
> Program in Computational Biology
> Division of Public Health Sciences
> Fred Hutchinson Cancer Research Center
> 1100 Fairview Ave. N, M1B514
> P.O. Box 19024
> Seattle, WA 981091024
>
> Email: [hidden email]
> Phone: (206) 6675791
> Fax: (206) 6671319
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel

