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

Niels Richard Hansen Niels.R.Hansen+lists at math.ku.dk
Thu Aug 26 23:18:14 CEST 2010



On 26/08/10 18.42, Martin Morgan wrote:
> 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

Oops, right.

>
> 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.

I believe that is true. If 'a' is put into the environment two levels
up (using 'browser'), it is found.

> 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.

But as I understand it, the scoping rules solve such problems and
locate the variable in any environment at a higher level? Replacing
the callGeneric by a direct call of myplus removes the problem, it
seems, though 'a' will still be three levels up.

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

I don't see how that solves the problem.

- Niels

>
> 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
>

-- 
Niels Richard Hansen                     Web:   www.math.ku.dk/~richard	
Associate Professor			 Email: Niels.R.Hansen at math.ku.dk
Department of Mathematical Sciences	        nielsrichardhansen at gmail.com
University of Copenhagen		 Skype: nielsrichardhansen.dk	
Universitetsparken 5			 Phone: +45 353 20783 (office)	
2100 Copenhagen Ø			        +45 2859 0765 (mobile)
Denmark



More information about the R-help mailing list