On Fri, Sep 22, 2017 at 10:28 AM, Iñaki Úcar <i.uca...@gmail.com> wrote: > 2017-09-22 19:04 GMT+02:00 Michael Lawrence <lawrence.mich...@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? >
There is formally no such thing as an S3 class. Just S3 objects with a class attribute. You could extend a base class with an S4 class, like setClass("IntegerWithUnits", slots=c(units="Units"), contains="integer"). Sure, that's a disruptive change, but it would be in the right direction. Extending base classes is always a risky proposition, as you've discovered. Ideally you would override every transformation in order to adjust or carry over the representation accordingly. The problem is that there's a huge amount of transformations available for base classes, mostly not encapsulated by generics. Other possibilities include: - Convincing someone to make %*% an internal S3 generic - Promoting %*% to an R-level S3 generic, which would only work with code that sees your namespace Hopefully others have better ideas, Michael > Iñaki > ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel