Why is callNextMethod()
not passing arguments as expected to the next method?
Say I have two hierarchical classes foo
and bar
(bar
is subclass of foo
) for which I have a method foobar
that can dispatch for both classes (i.e., has methods for both classes).
Furthermore, the method for the (sub)class bar
calls the method for foo
after some calculations with callNextMethod()
.
Both methods have the same additional argument (with default) that should be passed to the method for foo
, where only it is relevant.
setClass("foo", representation(x = "numeric"))
setClass("bar", contains = "foo")
setGeneric("foobar", function(object, ...) standardGeneric("foobar"))
setMethod("foobar", "foo", function(object, another.argument = FALSE, ...) {
print(paste("in foo-method:", another.argument))
if (another.argument) object@x^3
else object@x^2
})
setMethod("foobar", "bar", function(object, another.argument = FALSE, ...) {
print(paste("in bar-method:", another.argument))
object@x <- sqrt(object@x)
callNextMethod()
})
Problem description:
The arguments are not passed as expected, but the default values are taken from the method definition. Specifically, in the first method the argument is as specified in the call (TRUE
), however, it changes to FALSE
in the next method.
o1 <- new("bar", x = 4)
foobar(o1, another.argument = TRUE)
gives
[1] "in bar-method: TRUE"
[1] "in foo-method: FALSE"
[1] 4
I want the another.argument
to be passed to the next method so that it is TRUE
in the call to the foo
method, too.
From ?callNextMethod
I get that it should work as expected (i.e., the named argument is passed as it is in the call):
For a formal argument, say x, that appears in the original call, there is a corresponding argument in the next method call equivalent to x = x. In effect, this means that the next method sees the same actual arguments, but arguments are evaluated only once.
My second question: How can I pass another.argument to the next method. (I would really like to keep default arguments in both methods)
I think this has to do with the way a method with a signature different from the generic is defined (within a function .local)
> selectMethod(foobar, "bar")
Method Definition:
function (object, ...)
{
.local <- function (object, another.argument = FALSE, ...)
{
print(paste("in bar-method:", another.argument))
object@x <- sqrt(object@x)
callNextMethod()
}
.local(object, ...)
}
Signatures:
object
target "bar"
defined "bar"
The work-around is to either define the generic and methods to have the same signature
setGeneric("foobar",
function(object, another.argument=FALSE, ...) standardGeneric("foobar"),
signature="object")
or pass the arguments explicitly to callNextMethod
setMethod("foobar", "bar", function(object, another.argument = FALSE, ...) {
print(paste("in bar-method:", another.argument))
object@x <- sqrt(object@x)
callNextMethod(object, another.argument, ...)
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With