Hi all, I'm trying to implement the matrix multiplication operator, which is S4 generic, for an old-style S3 class. The following works as expected: x <- 1:10 class(x) <- "myClass" setOldClass("myClass") setGeneric("myMethod", function(x, y) standardGeneric("myMethod")) setMethod("myMethod", c("myClass", "myClass"), function(x, y) message("dispatched!")) myMethod(x, x) #> dispatched! but I don't understand why the following won't: setMethod("%*%", c("myClass", "myClass"), function(x, y) message("dispatched!")) x %*% x #> [,1] #> [1,] 385 Is this approach wrong? Regards, I?aki
The %*% function is a primitive. As it says in the documentation under ?Methods_Details Methods may be defined for most primitives, and corresponding metadata objects will be created to store them. Calls to the primitive still go directly to the C code, which will sometimes check for applicable methods. The definition of ?sometimes? is that methods must have been detected for the function in some package loaded in the session and ?isS4(x)? is ?TRUE? for the first argument (or for the second argument, in the case of binary operators). But:> isS4(x)[1] FALSE I think this behavior is in the interest of performance. It avoids adding S4 dispatch overhead to e.g. matrix objects. In general, it's best to define an S4 class when using S4 dispatch, but it sounds like you're stuck using some legacy S3 objects. In that case, one would normally define an S3 method for `%*%()` that delegates to a custom non-primitive generic, perhaps "matmult" in this case. But since %*% is not an S3 generic, that's not an option. It would help to hear more about the context of the problem. Michael On Fri, Sep 22, 2017 at 5:44 AM, I?aki ?car <i.ucar86 at gmail.com> wrote:> Hi all, > > I'm trying to implement the matrix multiplication operator, which is > S4 generic, for an old-style S3 class. The following works as > expected: > > x <- 1:10 > class(x) <- "myClass" > > setOldClass("myClass") > setGeneric("myMethod", function(x, y) standardGeneric("myMethod")) > setMethod("myMethod", c("myClass", "myClass"), function(x, y) > message("dispatched!")) > > myMethod(x, x) > #> dispatched! > > but I don't understand why the following won't: > > setMethod("%*%", c("myClass", "myClass"), function(x, y) message("dispatched!")) > > x %*% x > #> [,1] > #> [1,] 385 > > Is this approach wrong? > > Regards, > I?aki > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
2017-09-22 19:04 GMT+02:00 Michael Lawrence <lawrence.michael at gene.com>:> The %*% function is a primitive. As it says in the documentation under > ?Methods_Details > > Methods may be defined for most primitives, and corresponding > metadata objects will be created to store them. Calls to the > primitive still go directly to the C code, which will sometimes > check for applicable methods. The definition of ?sometimes? is > that methods must have been detected for the function in some > package loaded in the session and ?isS4(x)? is ?TRUE? for the > first argument (or for the second argument, in the case of binary > operators). > > But: >> isS4(x) > [1] FALSE > > I think this behavior is in the interest of performance. It avoids > adding S4 dispatch overhead to e.g. matrix objects.I see, thanks for the explanation.> In general, it's best to define an S4 class when using S4 dispatch, > but it sounds like you're stuck using some legacy S3 objects. In that > case, one would normally define an S3 method for `%*%()` that > delegates to a custom non-primitive generic, perhaps "matmult" in this > case. But since %*% is not an S3 generic, that's not an option. > > It would help to hear more about the context of the problem.This is a problem that Edzer Pebesma and I are facing in our packages units and errors respectively (you can find both on CRAN). They are designed in a similar way: units or errors are attached to numeric vectors as an attribute of an S3 class, and Ops, Math and Summary are redefined to cope with such units/errors. Then Edzer found that the %*% operator silently drops the attributes, so we were trying, without success, to set a method for our respective S3 classes to at least show a warning stating that the units/errors are being dropped. Ours are perfect use cases for S3 classes, and it would be a pitty if we have to switch everything to S4 just to show a warning. Clearly overkilling. Isn't there another way? I?aki