[R] WG: Reference classes: error with missing arguments in method calls

Martin Morgan mtmorgan at fhcrc.org
Mon Mar 7 02:32:22 CET 2011


On 03/06/2011 04:34 PM, Janko Thyson wrote:
> Dear list,
> 
> a while ago I posted this at r-devel but got no answers. Hope it’s okay to
> give it a shot again by cross-posting it here.

Hi Janko --
> 
> TIA for any comments,
> Janko
> 
> Von: Janko Thyson [mailto:janko.thyson.rstuff at googlemail.com] 
> Gesendet: Montag, 21. Februar 2011 00:58
> An: r-devel at r-project. org (r-devel at r-project.org)
> Betreff: Reference classes: error with missing arguments in method calls
> 
> Dear list,
> 
> I’m having problems in understanding an error that pops up in the context of
> missing arguments with methods of reference class objects.
> 
> Because of the following statement taken from ‘?referenceClass’, my ref
> class methods call explicit S4 methods:
> “Reference methods should be kept simple; if they need to do some
> specialized R computation, that computation should use a separate R function
> that is called from the reference method“
> 
> So a ref class would look like this:
> setRefClass(Class="Xmple", methods=list(foo=function(var.1, ...)
> fooMthd(.self=.self, var.1=var.1, ...))) 
> 
> I’d like to keep the generics defs as simple as possible, thus their only
> arg should be ‘.self’. The S4 methods are specified in a way that if ‘var.1’
> is missing, it will be assigned some default value (I know I could
> explicitly set the default value, yet I would like to rely on ‘missing()’
> for that). Now, my problem is that this works fine if the generic contains
> an argument ‘var.1’, but results in an error if it doesn’t. And I don’t
> quite understand why since it seems to be related to whether the S4 method
> is invoked from a call to a ref class method or not. Here’s an example which
> demonstrates when it works as planed and when the error occurs. I tried to
> keep as short as possible:
> 
> # 1) "Stand-alone" context
> setGeneric(name="fooMthd", def=function(.self, ...)
> standardGeneric("fooMthd"), signature=c(".self"))    
> 
> setMethod(f="fooMthd", signature=signature(.self="character"), 
>     definition=function(.self, var.1, ...){
>     cat("I'm having one additional argument compared to my generic:",
> sep="\n")
>     if(missing(var.1)) var.1 <- "some default value"
>     cat(paste("* var.1: ", var.1, sep=""), sep="\n")    
> })
> 
> fooMthd(.self="blabla", var.1="hello world!")
> fooMthd(.self="blabla") # Works.
> 
> #+++++
> 
> # 2) Reference class context
> setMethod(f="fooMthd", signature=signature(.self="Xmple"), 
>     definition=function(.self, var.1, ...){
>     cat("I'm having one additional argument compared to my generic:",
> sep="\n")
>     if(missing(var.1)) var.1 <- "some default value"
>     cat(paste("* var.1: ", var.1, sep=""), sep="\n")    
> })

try selectMethod("fooMthd", "Xmple") here, and you'll see

> selectMethod(fooMthd, "Xmple")
Method Definition:

function (.self, ...)
{
    .local <- function (.self, var.1, ...)
    {
        cat("I'm having one additional argument compared to my generic:",
            sep = "\n")
        if (missing(var.1))
            var.1 <- "some default value"
        cat(paste("* var.1: ", var.1, sep = ""), sep = "\n")
    }
    .local(.self, ...)
}

Notice how S4 deals with a method signature that is different from the
generic -- it creates a nested function .local with the method
signature, and `exposes' to the generic a wrapper with the generic
signature.

> setRefClass(Class="Xmple", methods=list(foo=function(var.1, ...)
> fooMthd(.self=.self, var.1=var.1, ...)))

> xmple <- getRefClass(Class="Xmple")$new()
> xmple$foo(var.1="hallo") 
> xmple$foo() # Does not work.
>
> #+++++
> 
> # 3) "Fixed generic" context
> setGeneric(name="fooMthd", def=function(.self, var.1, ...)
> standardGeneric("fooMthd"), signature=c(".self"))     
> 
> setMethod(f="fooMthd", signature=signature(.self="Xmple"), 
>     definition=function(.self, var.1, ...){
>     cat("I'm having one additional argument compared to my generic:",
> sep="\n")
>     if(missing(var.1)) var.1 <- "some default value"
>     cat(paste("* var.1: ", var.1, sep=""), sep="\n")    
> })

Since the generic and method have the same signature, S4 has

> selectMethod(fooMthd, "Xmple")
Method Definition:

function (.self, var.1, ...)
{
    cat("I'm having one additional argument compared to my generic:",
        sep = "\n")
    if (missing(var.1))
        var.1 <- "some default value"
    cat(paste("* var.1: ", var.1, sep = ""), sep = "\n")
}

no nested .local function.

Here's my mock-up of the first situation

  f0 <- function(x, ...) {
      .local <- function(x, y, ...) missing(y)
      .local(x, ...)
  }
  g0 <- function(x, y, ...) f0(x, y, ...)

the second situation

  f1 <- function(x, y, ...) missing(y)
  g1 <- function(x, y, ...) f1(x, y, ...)

and the evaluation

> g0()
[1] FALSE
> g1()
[1] TRUE

?missing says

     Currently 'missing' can only be used in the immediate body of the
     function that defines the argument, not in the body of a nested
     function or a 'local' call.  This may change in the future.

so the answer to your question somehow involves S4 representation of
methods with signatures different from the generic, how missing()
determines whether an argument is missing or not, and perhaps R's
scoping rules. I'm not sure that there's an easy story to tell here.

Martin

> 
> xmple$foo(var.1=" blabla") 
> xmple$foo() # Works.
> 
> I do understand that in the ref class ‘foo()’ has trouble passing an arg to
> ‘fooMthd()’ that hasn’t been specified. But why and how does simply
> including ‘var.1’ in the generic def fix this?
> 
> Thanks for any comments,
> Janko
> 
> R version 2.12.1 (2010-12-16)
> Platform: i386-pc-mingw32/i386 (32-bit)
> 
> locale:
> [1] LC_COLLATE=German_Germany.1252  LC_CTYPE=German_Germany.1252   
> [3] LC_MONETARY=German_Germany.1252 LC_NUMERIC=C                   
> [5] LC_TIME=German_Germany.1252    
> 
> attached base packages:
> [1] stats     graphics  grDevices utils     datasets  methods   base     
> 
> loaded via a namespace (and not attached):
> [1] codetools_0.2-6 tools_2.12.1  
> 
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.


-- 
Computational Biology
Fred Hutchinson Cancer Research Center
1100 Fairview Ave. N. PO Box 19024 Seattle, WA 98109

Location: M1-B861
Telephone: 206 667-2793



More information about the R-help mailing list