vctrs
vctrs copied to clipboard
@method required for vec_arith in R 4.0+, but not R 3.6.3?
Related to #1287.
I lost a bit of time trying to debug the fact that, in R 4.0, you must use @method for vec_arith. However, in R 3.6.3, @export is sufficient.
This is not made clear in https://vctrs.r-lib.org/articles/s3-vector.html#arithmetic-1. But I'm also a newb when it comes to S3 methods; perhaps it's obvious to experience folks.
Here is my vctrs_io class.
new_io <- function(x = double()) {
stopifnot(is.double(x))
vctrs::new_vctr(x, class = "vctrs_io")
}
# methods::setOldClass(c("vctrs_io", "vctrs_vctr"))
#' `io` vector
#'
#' This creates a double vector that represents bandwidth (GB/s).
#'
#' @import vctrs
#' @param x A numeric vector
#' @return An S3 vector of class `io`.
#' @export
#' @examples
#' io(c(1,3,9))
io <- function(x = double()) {
x <- vctrs::vec_cast(x, double())
new_io(x)
}
#' bandwidth units in Gb/s
#' @export
format.vctrs_io <- function(x, ...) {
paste0(format(vctrs::vec_data(x)), " Gb/s")
}
#' @param x an object to test
#' @export
#' @rdname io
is_io <- function(x) inherits(x, "vctrs_io")
# arith
#' @export
vec_arith.vctrs_io <- function(op, x, y, ...) {
UseMethod("vec_arith.vctrs_io", y)
}
#' @export
vec_arith.vctrs_io.default <- function(op, x, y, ...) {
vctrs::stop_incompatible_op(op, x, y)
}
#' @export
vec_arith.vctrs_io.vctrs_io <- function(op, x, y, ...) {
switch(
op,
"+" = ,
"-" = io(vctrs::vec_arith_base(op, x, y)),
"/" = vctrs::vec_arith_base(op, x, y),
vctrs::stop_incompatible_op(op, x, y)
)
}
#' @export
vec_arith.vctrs_io.numeric <- function(op, x, y, ...) {
switch(
op,
"/" = ,
"*" = new_io(vctrs::vec_arith_base(op, x, y)),
vctrs::stop_incompatible_op(op, x, y)
)
}
#' @export
vec_arith.numeric.vctrs_io <- function(op, x, y, ...) {
switch(
op,
"*" = new_io(vctrs::vec_arith_base(op, x, y)),
vctrs::stop_incompatible_op(op, x, y)
)
}
# types
#' @export
vec_ptype2.vctrs_io.vctrs_io <- function(x, y, ...) new_io()
#' @export
vec_ptype2.vctrs_io.double <- function(x, y, ...) double()
#' @export
vec_ptype2.double.vctrs_io <- function(x, y, ...) double()
# casts
#' @export
vec_cast.vctrs_io.vctrs_io <- function(x, to, ...) x
#' @export
vec_cast.vctrs_io.double <- function(x, to, ...) new_io(x)
#' @method vec_cast.double vctrs_io
#' @export
vec_cast.double.vctrs_io <- function(x, to, ...) vctrs::vec_data(x)
I throw this into a package under R/vctrs_io_class.R. Here is the NAMESPACE.
# Generated by roxygen2: do not edit by hand
S3method(format,vctrs_io)
S3method(vec_arith,numeric.vctrs_io)
S3method(vec_arith,vctrs_io.default)
S3method(vec_arith,vctrs_io.numeric)
S3method(vec_arith,vctrs_io.vctrs_io)
S3method(vec_cast,vctrs_io.double)
S3method(vec_cast,vctrs_io.vctrs_io)
S3method(vec_cast.double,vctrs_io)
S3method(vec_ptype2,double.vctrs_io)
S3method(vec_ptype2,vctrs_io.double)
S3method(vec_ptype2,vctrs_io.vctrs_io)
export(io)
export(is_io)
export(vec_arith.vctrs_io)
import(vctrs)
R 3.6.3 -- Works fine
❯ R --vanilla
R version 3.6.3 Patched (2020-04-28 r78687) -- "Holding the Windsock"
Copyright (C) 2020 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin15.6.0 (64-bit)
...
> devtools::load_all(here::here())
> sessionInfo()
R version 3.6.3 Patched (2020-04-28 r78687)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Catalina 10.15.7
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] io_0.0.0.9000
loaded via a namespace (and not attached):
[1] rstudioapi_0.13 magrittr_2.0.1 usethis_2.0.1 devtools_2.3.2
[5] pkgload_1.2.0 here_1.0.1 R6_2.5.0 rlang_0.4.10
[9] fastmap_1.1.0 tools_3.6.3 pkgbuild_1.2.0 sessioninfo_1.1.1
[13] cli_2.3.1 withr_2.4.1 ellipsis_0.3.1 remotes_2.2.0
[17] assertthat_0.2.1 rprojroot_2.0.2 lifecycle_1.0.0 crayon_1.4.1
[21] processx_3.4.5 purrr_0.3.4 callr_3.5.1 vctrs_0.3.7
[25] fs_1.5.0 ps_1.6.0 testthat_3.0.2 memoise_2.0.0
[29] glue_1.4.2 cachem_1.0.4 compiler_3.6.3 desc_1.3.0
[33] prettyunits_1.1.1
> new_io(c(r=1, w=2)) + new_io(c(r=1, w=4))
<vctrs_io[2]>
r w
2 Gb/s 6 Gb/s
R 4.0.0 -- Error
❯ R --vanilla
R version 4.0.0 (2020-04-24) -- "Arbor Day"
Copyright (C) 2020 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin17.0 (64-bit)
...
> devtools::load_all(here::here())
> sessionInfo()
R version 4.0.0 (2020-04-24)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Catalina 10.15.7
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] io_0.0.0.9000
loaded via a namespace (and not attached):
[1] rstudioapi_0.11 magrittr_1.5 usethis_1.6.1 devtools_2.3.0
[5] pkgload_1.1.0 here_0.1 R6_2.4.1 rlang_0.4.10
[9] tools_4.0.0 pkgbuild_1.0.8 sessioninfo_1.1.1 cli_2.4.0
[13] withr_2.4.1 ellipsis_0.3.1 remotes_2.1.1 digest_0.6.25
[17] assertthat_0.2.1 rprojroot_1.3-2 crayon_1.3.4 processx_3.5.1
[21] callr_3.6.0 vctrs_0.3.7 fs_1.4.1 ps_1.6.0
[25] testthat_3.0.2 memoise_1.1.0 glue_1.4.1 compiler_4.0.0
[29] desc_1.2.0 backports_1.1.7 prettyunits_1.1.1
> new_io(c(r=1, w=2)) + new_io(c(r=1, w=4))
Error: <vctrs_io> + <vctrs_io> is not permitted
Run `rlang::last_error()` to see where the error occurred.
traceback() points towards an issue with S3 methods.
> traceback()
9: stop(fallback)
8: signal_abort(cnd)
7: abort(message, class = c(class, "vctrs_error"), ...)
6: stop_vctrs(message, class = c(class, "vctrs_error_incompatible"),
x = x, y = y, details = details, ...)
5: stop_incompatible(x, y, op = op, details = details, ..., message = message,
class = c(class, "vctrs_error_incompatible_op"))
4: stop_incompatible_op(op, x, y)
3: vec_arith.default("+", e1, e2)
2: vec_arith("+", e1, e2)
1: `+.vctrs_vctr`(new_io(c(r = 1, w = 2)), new_io(c(r = 1, w = 4)))
If you source directly, issue is resolved (but not conducive to package development):
> source(here::here("R/vctrs_io_class.R"))
> new_io(c(r=1, w=2)) + new_io(c(r=1, w=4))
<vctrs_io[2]>
r w
2 Gb/s 6 Gb/s
You do currently have to supply @method for vec_arith. There was a change in R 4.0.0 related to S3 method lookup, and I'm pretty sure that is why it "works" in 3.6.3, but not in 4.0.0. The news bullet for the change is:
S3 method lookup now by default skips the elements of the search path between the global and base environments.
The eventual plan is for vec_arith to work like vec_ptype2/vec_cast where you only have to use @export.
We should probably mention that you currently have to do this in the Other Helpers section here: https://vctrs.r-lib.org/articles/s3-vector.html#other-helpers
You can use this as a guide for now: https://github.com/r-lib/clock/blob/430514ea797fec8d47ba4f26e02085f5155de8c2/R/duration.R#L751-L814