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")
)
}
)
source to share
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.
source to share