10

Can someone explain why overloading an operator on an old-style S3 class which is registered does not work as expected while when defining a new class and overloading the operators does work.

As shown in the following examples.

This does not work.

require(ff) 
setOldClass(Classes=c("ff_vector")) 
setMethod( 
  f="*", 
  signature = signature(e1 = c("ff_vector"), e2 = c("ff_vector")), 
  definition = function (e1, e2){ 
        print("S3 setOldClass")
        e1[] * e2[] 
    } 
) 
ff(1:10) * ff(1:10) 
Error in ff(1:10) * ff(1:10) : non-numeric argument to binary operator

But this works.

setClass("myff_vector", representation(x="ff_vector"))
setMethod( 
  f="*", 
  signature = signature(e1 = c("myff_vector"), e2 = c("myff_vector")), 
  definition = function (e1, e2){ 
        print("S4 setOldClass")
        e1@x[] * e2@x[] 
    } 
) 
new("myff_vector", x = ff(1:10)) * new("myff_vector", x = ff(1:10))
[1] "S4 setOldClass"
[1]   1   4   9  16  25  36  49  64  81 100
  • This is almost certainly the same issue behind this [https://stackoverflow.com/questions/55019663/non-numeric-argument-to-binary-operator-when-defining-a-data-frame-method-for/55021034#55021034] question (the objects themselves need to be S4, in the sense of `isS4()` on at least one of them needs to be TRUE, and `setOldClass` is not sufficient for that). – JDL Dec 16 '19 at 16:56

2 Answers2

0

Attempt at a partial answer: In help('Methods'), in the Generic Functions section, it is stated:

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).

Back to your problem, * is a primitive, and:

library(ff)
setOldClass("ff_vector")
isS4(ff(1:10))
[1] FALSE

So from what I understand, it is not possible to define a method for primitive functions on S3 classes, even if you use setOldClass().

Karl Forner
  • 4,175
  • 25
  • 32
0

It's not really clear from the question whether this counts as an answer, but for the record, the operator could be overloaded in plain and simple S3-style, without any setOldClass or S4:

`*.ff_vector` <- function(x, y) {
  print("hi")
  x[] * y[]
}

> ff(1:10) * ff(1:10)
[1] "hi"
[1]   1   4   9  16  25  36  49  64  81 100
RolandASc
  • 3,863
  • 1
  • 11
  • 30