[R] Passing arguments between S4 methods fails within a function:bug? example with raster package.

Martin Morgan mtmorgan at fhcrc.org
Thu Aug 26 18:42:06 CEST 2010


  On 8/26/2010 8:43 AM, Niels Richard Hansen wrote:
> setGeneric("myplus",function(x,y,...) standardGeneric("myplus"))
> setMethod("myplus",c(x="numeric",y="numeric"),
>           function(x,y,z=0) x+y+z
>           )
> setMethod("myplus",c(x="numeric",y="list"),
>           function(x,y,...) callGeneric(x,unlist(y),...)
>           )
>
> myplus(1,1)   ## 2; OK
> myplus(1,1,1) ## 3; OK
>
> myplus(1,list(1)) ## 2; OK
> myplus(1,list(1),z=1) ## 3; OK
>
> a.c1 <- 1
> myplus(1,list(1),z=a.c1) ## 3; OK
>
> test <- function(x,y) {
>   a.c <- 1    ## Problem occurs when using '.' in variable name
>   myplus(a,y,z=a.c)
> }
>
> test(1,list(1)) ## error
> test(1,1)  ## 3; OK

I get an error in both instances, because in fact there is no variable 
'a' defined (anywhere) in the session. I do get your results if I define 
a global variable a <- 2

The reason for the original problem can be seen by looking at how the 
methods are implemented (I added parentheses in the setMethod calls for 
clarity)

 > showMethods(myplus, includeDef=TRUE)
Function: myplus (package .GlobalEnv)
x="numeric", y="list"
function (x, y, ...)
{
     callGeneric(x, unlist(y), ...)
}


x="numeric", y="numeric"
function (x, y, ...)
{
     .local <- function (x, y, z = 0)
     {
         x + y + z
     }
     .local(x, y, ...)
}

and in particular the c("numeric", "numeric") method has an extra 
argument z, and so has a nested .local function. This is how the methods 
package deals with method signatures that differ from the generic.

I think, roughly, that when c("numeric", "numeric") tries finally to 
resolve it's argument 'x', it looks for a variable 'a' in the 
environment two levels up (method --> generic) from where it is being 
resolved. This is fine if the method has no .local environment (e.g., if 
c("numeric", "numeric") where defined as function(x, y, ...) { x +y }). 
I think that there is no general solution to this; the user could 
callGeneric or evaluate symbols from arbitrarily nested functions within 
either the calling or called methods themselves, and could arrive at a 
particular method through callGeneric or other routes (e.g., 
callNextMethod) that are not consistent in terms of the implied frame of 
evaluation. I could be mistaken.

A simple solution is to provided named arguments to callGeneric, e.g., 
callGeneric(x=x, y=unlist(y), ...).

These issues are likely to cause problems for eval / substitute 
expressions like the one posted by Joris yesterday, where there are 
implicit assumptions about the environment in which the experession is 
being evaluated.

Martin



More information about the R-help mailing list