Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems passing arguments with callNextMethod() in R

My question:

Why is callNextMethod() not passing arguments as expected to the next method?

Situation:

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)

like image 467
Henrik Avatar asked Aug 25 '11 12:08

Henrik


1 Answers

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, ...)
})
like image 120
Martin Morgan Avatar answered Sep 29 '22 04:09

Martin Morgan