R additional arguments for S4 setMethod

I am interested in installing new methods for common functions. For example, let's say I have a new class (for example coolClass

). I could write a wrapper to compute log10

this class and easily set a method with the following code:

setMethod("Math", c(x="coolClass"),
          function(x)
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   stop("Undefined operation")
            )
          }
)

      

However, I cannot figure out how to set a method to pass multiple arguments. For example, a general method log

. Running getGeneric("log")

shows the following:

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2f9a958>
<environment: 0x2f937f0>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

      

Seeing this, I expect to be able to write the following to pass an optional argument base

.

setMethod("Math", signature(x="coolClass",...),
          function(x, ...)
          {
            op = .Generic[[1]]
            switch(op,
                   `log` = log_for_coolClass(x, ...),
                   stop("Undefined operation")
            )
          }
)

      

But I am getting the following error:

Error in matchSignature(signature, fdef, where) : 
  '...' used in an incorrect context

      

Tried without ...

in signature

, I get another error:

Error in rematchDefinition(definition, fdef, mnames, fnames, signature) : 
   methods can add arguments to the generic ‘Math’ only if '...' is an argument to the generic

      

It seems strange to me what getGeneric

log shows ...

in the method.

Any ideas? Is there a way to capture additional arguments? I'm trying to get more comfortable with S4 methods, but I'm confused as to how to pass optional arguments. If this is not possible, I would appreciate it if someone could explain how the function works log

, for example, given that this function is part of a group Math

but takes multiple arguments.

Update

Curiously, as noted below, I can use setMethod

directly on log

with the following:

setMethod("log", signature(x="big.matrix"),
          function(x, base=exp(1))
            {
            log_for_coolClass(x, base=base)
          }
          )

      

However, this doesn't quite calm my curiosity. For example, it seems strange that it repeats itself in the code if I create many new methods in a group Math

. Ideally, it would look something like this:

setMethod("Math", c(x="coolClass"),
          function(x, base=exp(1))
          {
            op = .Generic[[1]]
            switch(op,
                   `log10` = log10_for_coolClass(x),
                   `log` = log_for_coolClass(x, base=base),
                   stop("Undefined operation")
            )
          }
)

      

+3


source to share


1 answer


Here the class

.A <- setClass("A", representation(x="numeric"))

      

For such a function as log

, we have

> getGeneric("log")
standardGeneric for "log" defined from package "base"
  belonging to group(s): Math 

function (x, ...) 
standardGeneric("log", .Primitive("log"))
<bytecode: 0x2b41b28>
<environment: 0x2b39df8>
Methods may be defined for arguments: x
Use  showMethods("log")  for currently available ones.

      

where the signature includes ...

. Therefore we write

setMethod("log", "A", function(x, ...) {
    log(x@x, ...)
})

      

and have success

> log(.A(x=c(1, 2, NA)))
[1] 0.0000000 0.6931472        NA
> log(.A(x=c(1, 2, NA)), base=2)
[1]  0  1 NA

      

Next: log10

> getGeneric("log10")
standardGeneric for "log10" defined from package "base"
  belonging to group(s): Math 

function (x) 
standardGeneric("log10", .Primitive("log10"))
<bytecode: 0x2b4a700>
<environment: 0x2b43138>
Methods may be defined for arguments: x
Use  showMethods("log10")  for currently available ones.

      

There are no ...

arguments in general, so we basically get stuck - write our own generic and implement methods that include ...

, or write log10, an A method that has no argument ...

.



The same principle ...

applies to group generics - the general set of Math-groups has no points

> getGeneric("Math")
groupGenericFunction for "Math" defined from package "base"

function (x) 
standardGeneric("Math")
<bytecode: 0x2771d40>
<environment: 0x275ee20>
Methods may be defined for arguments: x
Use  showMethods("Math")  for currently available ones.

      

therefore our method (which implements all Math operations, not just the log, note that we usually do not reference. Explicitly, objects of our class can be

setMethod("Math", "A", function(x) {
    callGeneric(x@x)
})

      

and now we have methods for all math functions like

> sqrt(.A(x=1:4))
[1] 1.000000 1.414214 1.732051 2.000000

      

also our version of the journal accepting ... is still available, so we can define the behavior of our class for all the math tricks of Math and provide specialized implementations for specific generics.

There is probably a bug in the implementation of these generic generics that needs to be addressed. If in the new session we have defined our class and Math

generic, but not a function log

with an argument ...

, we can still call

> log(.A(x=1:4))
[1] 0.0000000 0.6931472 1.0986123 1.3862944
> log(.A(x=1:4), base=2)
[1] 0.0000000 0.6931472 1.0986123 1.3862944

      

where the second argument is ignored, but should actually throw an error.

+1


source







All Articles