-
Notifications
You must be signed in to change notification settings - Fork 42
Description
Summary:
Docs say S7 “behaves like S3.” For base matrices without an explicit class attribute beyond the implicit c("matrix","array", <type>), S3 would try f.matrix before type. In S7, a method registered with new_S3_class("matrix") is not found. Dispatch instead looks for <double> / <integer> / <logical> and errors.
Minimal reproducible example:
library(S7)
# generic
example_generic <- S7::new_generic(
"example_generic",
dispatch_args = "x",
fun = function(x, ...) S7::S7_dispatch()
)
# method intended for base matrices
S7::method(example_generic, S7::new_S3_class("matrix")) <- function(x, ...) {
"matrix"
}
m <- matrix(c(0,1,0,0), 2, 2)
class(m)
# [1] "matrix" "array"
example_generic(m)
# Error: Can't find method for `example_generic(<double>)`.Expected:
"matrix method" is called, analogous to S3 where .class2(m) returns c("matrix","array","double","numeric") and f.matrix is tried before type.
Actual:
S7 reports no method for <double>. The S3<matrix> method is ignored.
Notes and related behavior:
-
Adding a base-type method fixes it, but that forces users to implement three methods (
<double>,<integer>,<logical>) instead of one for"matrix". -
For Matrix package S4 classes,
methods::getClass("Matrix")works as expected:if (requireNamespace("Matrix", quietly = TRUE)) { S7::method(example_generic, methods::getClass("Matrix")) <- function(x, ...) { "Matrix" } example_generic(Matrix::Matrix(m, sparse = TRUE)) # returns "Matrix" }
Questions / proposed resolutions:
-
Should S7's dispatch system look at S3/S4 classes first before typeof()?
-
If not, can S7 expose canonical base “dimension” classes like
S7::class_matrixandS7::class_arrayto avoid three separate type methods?- Requiring
<integer>/<double>/<logical>methods conflates matrices with atomic vectors, so dispatch can ignore matrix semantics (2D shape, dimnames, square checks) and yield behavior different from an intendedmatrixmethod.
- Requiring
-
At minimum, docs should clarify that base matrices dispatch by atomic storage type, not by
"matrix", and show the recommended pattern.
I am sorry, if I have misunderstood something here, but I am working on a package where methods that work for matrix objects are important.