Suggested improvement for "looser" storage rules of Date,POSIXct in R>=4.5.0
x = Sys.Date()
y = seq(Sys.Date(), length.out = 1L, by=1L)
waldo::compare(x, y)
# `old` is an S3 object of class <Date>, a double vector
# `new` is an S3 object of class <Date>, an integer vector
waldo::compare(format(x), format(y))
# ✔ No differences
I think this makes writing tests a bit too fussy -- mostly we don't care about this storage difference. Roughly, only R itself should care if behavior of the class differs depending on the storage mode; some exceptions to that can be tested with e.g. expect_type() if needed.
To expand a bit more, I think testthat already has a way to capture this distinction: equal vs identical.
library(testthat)
local_edition(3)
expect_equal(1L, 1.0)
expect_identical(1L, 1.0)
#> Error: 1L (`actual`) not identical to 1 (`expected`).
#>
#> `actual` is an integer vector (1)
#> `expected` is a double vector (1)
expect_equal(.Date(1L), .Date(1.0))
expect_identical(.Date(1L), .Date(1.0))
#> Error: .Date(1L) (`actual`) not identical to .Date(1) (`expected`).
#>
#> `actual` is an S3 object of class <Date>, an integer vector
#> `expected` is an S3 object of class <Date>, a double vector
Created on 2025-07-07 with reprex v2.1.1
Thanks... I still like the compare_proxy approach, but I can see it either way. I do think .Date(1L) and .Date(1.0) are "identical" -- if the class authors don't want us to care about the storage type, downstream test authors shouldn't either, is how I would summarize my (weak) thinking?
Just like in other cases with compare_proxy methods, if our use case truly requires us to compare the storage type, we can still test that directly, but it should be a rare exception.