From jmc at R-project.org  Fri Aug  5 21:18:50 2005
From: jmc at R-project.org (John Chambers)
Date: Fri, 05 Aug 2005 15:18:50 -0400
Subject: [Rd] S4 generating function
In-Reply-To: <Pine.OSF.4.58.0508051031080.304121@odin.mdacc.tmc.edu>
References: <Pine.OSF.4.58.0508050253370.278029@odin.mdacc.tmc.edu>
	<42F36C13.5060803@R-project.org>
	<Pine.OSF.4.58.0508051031080.304121@odin.mdacc.tmc.edu>
Message-ID: <42F3BB9A.2080609@R-project.org>

Re:
 > If I understand your description correctly, the problem is
 > passing both named and unnamed arguments to callNextMethod().

No, as I said the distinction is a potential bug in callNextMethod 
_whenever_ it gets explicit arguments.  (At the moment, it seems to be a 
bug in substitute() or else a different interpretation of that function 
from the one in the Blue Book.  But I've only looked a little.)

So to work around it you have to be able to do callNextMethod() with no 
arguments.

Just at a guess, you may be able to do that if you avoid redefining the 
formal arguments for the initialize() method.  Leave them as .Object, 
... and extract the id= component.
   dotArgs <- list(...)
   id <- dotArgs$id

Or, wait for a fix.  There should at least be one in r-devel sometime 
fairly soon.


Paul Roebuck wrote:

> On Fri, 5 Aug 2005, John Chambers wrote:
> 
> 
>>Paul Roebuck wrote:
>>
>>
>>>Can someone explain what the problem is when I use the
>>>generating function? And how to get debug() to stop in
>>>the Superclass initialize method?
>>>[SNIP code & output]
>>
>>Now, the specific example.  There are 3 special features used:
>>1. Nonstandard arguments for the initialize method (its official
>>arguments are (.Object, ...))
>>
>>2. callNextMethod
>>
>>3. within callNextMethod, providing explicit arguments.  The simple case
>>is callNextMethod(), which passes on the arguments to the current method.
>>
>>Turns out that it's the third step that finds a bug in the heuristics
>>used by callNextMethod to construct the actual call.
>>
>>In your example, you don't need the explicit arguments since they just
>>replicate the formal arguments to initialize().  If you omit them, the
>>computation is simpler & works.
>>
>>The bug can probably be fixed, but until 2.2 comes out at least, you
>>need to stick to the simpler callNextMethod().
>>[SNIP modified code]
> 
> 
> Thank you for your help. Unfortunately, this is a case where
> posting the simplest code necessary to display the bug works
> against the poster. Actual code uses external pointers but
> this revision shows more of the general concept.
> 
> If I understand your description correctly, the problem is
> passing both named and unnamed arguments to callNextMethod().
> Can I [easily] do either of these things to avoid the bug?
> 
>   1) somehow add an argument to 'dots' and invoke callNextMethod()
>      without arguments?
>   2) parse 'dots' and invoke callNextMethod() with a completely
>      named argument list?
> 
> 
> ------ revised source -------
> setClass("Superclass",
>          representation(.values = "integer",
>                         id      = "character"),
>          contains = "VIRTUAL")
> 
> setMethod("initialize",
>           signature(.Object = "Superclass"),
>           function(.Object, .values = NULL, id = "") {
>               cat("initialize (Superclass)", "\n")
>               if (!is.null(.values)) {
>                   cat("\t.values =", .values, "\n")
>                   .Object at .values <- .values
>               }
>               if (length(id) > 0) {
>                   cat("\tid =", id, "\n")
>                   .Object at id <- id
>               }
>               .Object
>           })
> 
> setClass("Subclass",
>          contains = "Superclass")
> 
> setMethod("initialize",
>           signature(.Object = "Subclass"),
>           function(.Object, count = 1, ...) {
>               cat("initialize (Subclass)", "\n")
>               dots <- list(...)
>               cat("\t... =");str(dots);cat("\n")
>               .values = integer(count)
>               callNextMethod(.Object, .values = .values, ...)
>           })
> 
> Subclass <- function(count, id = "") {
>     new("Subclass", count, id = id)
> }
> 
> cat("*** Create class using new() ***\n")
> str(new("Subclass", id = "test0"))
> str(new("Subclass", count = 3, id = "test1"))
> 
> cat("*** Create class using generating function ***\n")
> #trace("initialize", signature = "Subclass", browser)
> str(Subclass(count = 3, id = "test2"))
> 
> ----------------------------------------------------------
> SIGSIG -- signature too long (core dumped)
>



[Rd] S4 generating function
John Chambers