From hpages at fhcrc.org  Fri Jun 15 20:28:10 2007
From: hpages at fhcrc.org (Herve Pages)
Date: Fri, 15 Jun 2007 11:28:10 -0700
Subject: [Rd] Missing args with a default value in S4 methods
In-Reply-To: <46729040.9030706@r-project.org>
References: <467199D9.6090205@fhcrc.org> <46729040.9030706@r-project.org>
Message-ID: <4672DA3A.3080607@fhcrc.org>

John Chambers wrote:
> This has essentially nothing to do with methods, but rather with the
> treatment of missing arguments.
> 
> Consider:
>> foo <- function(x,...)bar(x,...)
>> bar <- function(x, y=12, z, ...) {cat(missing(y), "\n"); cat(y, "\n")}
> 
> This is the same argument-matching as your example, since the generic
> and method have different formal arguments.  And indeed,
> 
>> foo("a",,z=99)
> TRUE
> Error in cat(y, "\n") : argument is missing, with no default
> 
> The error message is correct, but the argument in question is not "y"
> but "..1".  This is constructed and passed down as a special R object
> representing "missing-argument-with-no-default".   (Splus would have
> worked as you expected, because missingness there is a property of the
> function call, not of the object corresponding to the formal argument.)

Thanks John for the clarification! I can see why, _technically speaking_, things
behave how they behave.

Note that what happens with default arguments in methods is not always the same
as with normal functions so it's not always possible to predict what is actually
going to happen... Here is an example:

1) Default arg in the method:

   o generic + method:
     > bar <- function(x, y=12, z) {cat(missing(y), "\n"); cat(x, y, z, "\n")}
     > setGeneric("mygen", signature=c("x", "z"), function(x, y, z) standardGeneric("mygen"))
     > setMethod("mygen", c("ANY", "ANY"), bar)
     > mygen("aa", , "bb")
     TRUE
     Error in cat(x, y, z, "\n") : argument "y" is missing, with no default

   o normal functions:
     > foo <- function(x, y, z) bar(x, y, z)
     > foo("aa", ,"bb")
     TRUE
     Error in cat(x, y, z, "\n") : argument "y" is missing, with no default

   Behaviour is the same.

2) Default arg in the generic:

   o generic + method: example 1) shows that if I want a default value
     for y, it should be put in the generic rather than in the method:
     > bar <- function(x, y, z) {cat(missing(y), "\n"); cat(x, y, z, "\n")}
     > setGeneric("mygen", signature=c("x", "z"), function(x, y=12, z) standardGeneric("mygen"))
     > setMethod("mygen", c("ANY", "ANY"), bar)
     > mygen("aa", , "bb")
     TRUE
     aa 12 bb

   o normal functions:
     > foo <- function(x, y=12, z) bar(x, y, z)
     > foo("aa", ,"bb")
     FALSE
     aa 12 bb

   Behaviour is _almost_ the same!

3) Default arg in the generic _and_ in the method:

   o generic + method:
     > bar <- function(x, y=999, z) {cat(missing(y), "\n"); cat(x, y, z, "\n")}
     > setMethod("mygen", c("ANY", "ANY"), bar)
     > mygen("aa", , "bb")
     TRUE
     aa 999 bb

     Not what I would expect!

   o normal functions:
     > foo("aa", ,"bb")
     FALSE
     aa 12 bb

     Much better.

I'm sure there is a _technical_ explanation for this (with probably some lazy evaluation
involved) but I find the current behaviour confusing and very hard to predict.

Cheers,
H.


> 
> 
> Herve Pages wrote:
>> Hi,
>>
>>
>> Strange things happen with missing args in S4 methods:
>>
>>   > setGeneric("mygen", signature="x", function(x, ...)
>> standardGeneric("mygen"))
>>   [1] "mygen"
>>
>>   > setMethod("mygen", "character", function(x, y=12, z, ...)
>> {cat(missing(y), "\n"); cat(y, "\n")})
>>   [1] "mygen"
>>
>>   > mygen("aa", z=99)
>>   TRUE
>>   12
>>
>>   > mygen("aa", , 99)
>>   TRUE
>>   Error in cat(y, "\n") : argument is missing, with no default
>>                                       ^^^^^^^       ^^^^^^^^^^
>>                                        TRUE          NOT TRUE!
>>
>>
>> For "normal" functions, things work as expected:
>>
>>   > myfun <- function(x, y=12, z, ...) {cat(missing(y), "\n"); cat(y,
>> "\n")}
>>
>>   > myfun("aa", z=99)
>>   TRUE
>>   12
>>
>>   > myfun("aa", , 99)
>>   TRUE
>>   12
>>
>> And with S3 generics too:
>>
>>   > dd <- data.frame(aa=letters[1:9], ii=9:1)
>>   > head(dd, z="ignored")
>>     aa ii
>>   1  a  9
>>   2  b  8
>>   3  c  7
>>   4  d  6
>>   5  e  5
>>   6  f  4
>>
>>   > head(dd, , "ignored")
>>     aa ii
>>   1  a  9
>>   2  b  8
>>   3  c  7
>>   4  d  6
>>   5  e  5
>>   6  f  4
>>
>> Cheers,
>> H.
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
>>   
>



[Rd] Missing args with a default value in S4 methods
Herve Pages