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_matrix and S7::class_array to 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 intended matrix method.
-
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.
Summary:
Docs say S7 “behaves like S3.” For base matrices without an explicit
classattribute beyond the implicitc("matrix","array", <type>), S3 would tryf.matrixbefore type. In S7, a method registered withnew_S3_class("matrix")is not found. Dispatch instead looks for<double>/<integer>/<logical>and errors.Minimal reproducible example:
Expected:
"matrix method"is called, analogous to S3 where.class2(m)returnsc("matrix","array","double","numeric")andf.matrixis tried before type.Actual:
S7 reports no method for
<double>. TheS3<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: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?<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.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.