Jens Heumann
2021-Jan-22 20:35 UTC
[Rd] Inconsistency of c.Date: non-commutativity and non-integer Value
Dear r-devel, Today I came across what I would call inconsistencies in the `c.Date` method compared to what happens when concatenating other classes: 1. Non-commutativity: The type in the arrangements of the elements does matter (first element is critical), 2. the resulting value is numeric instead of expected integer (as in the case with factors). > ## Examples#################################################################### > ## 1. Non-commutativity: > c(.1, Sys.Date()) [1]???? 0.1 18649.0 > c(as.integer(.1), Sys.Date()) [1]???? 0 18649 > ## whereas: > c(Sys.Date(), .1) Error in as.Date.numeric(e) : 'origin' must be supplied > c(Sys.Date(), as.integer(.1)) Error in as.Date.numeric(e) : 'origin' must be supplied > > ## 2. Numeric instead of numeric value > str(c(as.integer(.1), Sys.Date())) ?num [1:2] 0 18649? ## not integer > ################################################################################ I'm not sure if `c.Date` should redefined, since there would probably be many more classes to consider. However, the error message "'origin' must be supplied" cannot be served by the user and appears to me like an imperfection in the design. It would be desirable if `c.Date` harmonizes with the hierarchy stated in `?c`: "NULL < raw < logical < integer < double < complex < character < list < expression. [...] factors are treated only via their internal integer codes" and behaves best like a factor (and also throws integer values as in 2. above). Or maybe disabling non-dates at all `if (!all(sapply(list(Sys.Date(), .1), "class") == "Date")) stop...`, but this is a little beyond my knowledge. Anyway, I hope my remark is of relevance and contributes to the continuous development of our great programming language R! Best, Jens
Dirk Eddelbuettel
2021-Jan-22 21:17 UTC
[Rd] Inconsistency of c.Date: non-commutativity and non-integer Value
On 22 January 2021 at 21:35, Jens Heumann wrote: | Dear r-devel, | | Today I came across what I would call inconsistencies in the `c.Date` | method compared to what happens when concatenating other classes: 1. | Non-commutativity: The type in the arrangements of the elements does | matter (first element is critical), 2. the resulting value is numeric | instead of expected integer (as in the case with factors). | | > ## | Examples#################################################################### | > ## 1. Non-commutativity: | > c(.1, Sys.Date()) | [1]???? 0.1 18649.0 | > c(as.integer(.1), Sys.Date()) | [1]???? 0 18649 | > ## whereas: | > c(Sys.Date(), .1) | Error in as.Date.numeric(e) : 'origin' must be supplied | > c(Sys.Date(), as.integer(.1)) | Error in as.Date.numeric(e) : 'origin' must be supplied | > | > ## 2. Numeric instead of numeric value | > str(c(as.integer(.1), Sys.Date())) | ?num [1:2] 0 18649? ## not integer | > | ################################################################################ | | | I'm not sure if `c.Date` should redefined, since there would probably be | many more classes to consider. However, the error message "'origin' must | be supplied" cannot be served by the user and appears to me like an | imperfection in the design. | | It would be desirable if `c.Date` harmonizes with the hierarchy stated | in `?c`: "NULL < raw < logical < integer < double < complex < character | < list < expression. [...] factors are treated only via their internal | integer codes" and behaves best like a factor (and also throws integer | values as in 2. above). | | Or maybe disabling non-dates at all `if (!all(sapply(list(Sys.Date(), | .1), "class") == "Date")) stop...`, but this is a little beyond my | knowledge. | | Anyway, I hope my remark is of relevance and contributes to the | continuous development of our great programming language R! Nice analysis, well done. Sadly it is also a "known feature" of the c() operator and documented as such -- S3 class attributes drop. C'est la vie.>From ?c?c? is sometimes used for its side effect of removing attributes except names, for example to turn an array into a vector. ?as.vector? is a more intuitive way to do this, but also drops names. Note that methods other than the default are not required to do this (and they will almost certainly preserve a class attribute). I have into that trap approximately 4.56e8 times in this idiom > for (d in Sys.Date() + 0:2) print(d) [1] 18649 [1] 18650 [1] 18651 > Eventually one learns to switch to an iterator, and to pick the dates from a vector preserving their class. Dirk -- https://dirk.eddelbuettel.com | @eddelbuettel | edd at debian.org