It's a bug resulting from the combination of:
 1. multiple recursive levels of callNextMethod()
 2. nonstandard arguments in the method definition; that is, (.Object, 
x) vs .Object, ...) for the generic.

Specifically, the callNextMethod code tries to build up a list of 
"excluded" classes, but in this example seems to fail.  So the 
nextMethod selected for class "B", when it goes to find the next^2 
method, forgets to exclude class "C"; hence it goes back to the "C" 
method & so infinite recursion.

To see what's happening, use trace(callNextMethod, recover) or equivalent.

The computation in addNextMethod, callNextMethod, etc. is all very 
heuristic (aka "kludgey") code, so it's not clear how easy a fix would 
be.  The desirable route would be a better treatment of nonstandard 
arguments, but that may require digging deeper into the R evaluator than 
I've had the nerve to do so far.

Meanwhile, a work around is to avoid mechanism 2 if you want to use 
mechanism 1.  This may require separating out the guts of each method 
from the callNextMethod() part, with that part coming in a method 
definiton with standard arguments.

With the alternative definition below, all is well (if not very useful):
 > new("C", a=1,b=2,c=3)
in C
in B
in A
An object of class "C"
Slot "c":
[1] 3

Slot "b":
[1] 2

Slot "a":
[1] 1

using the methods:

setMethod("initialize", signature(.Object="A"),
          function(.Object, ...) {
              cat("in A\n")
              callNextMethod()
          })

setMethod("initialize", signature(.Object="B"),
          function(.Object, ...) {
              cat("in B\n")
              callNextMethod()
          })

setMethod("initialize", signature(.Object="C"),
          function(.Object, ...) {
              cat("in C\n")
              callNextMethod()
          })


Seth Falcon wrote:

>Hi,
>
>Given a simple three class hierarchy: A <-- B <-- C
>
>I want to define an initialize method for each class such that when I
>call new("C", x=5), the initialize methods for A and B are used to
>incrementally build the object.
>
>When I do what seems obvious to me using callNextMethod, I get an
>infinite recursion.  An example follows...
>
>setClass("A", representation(a="numeric"))
>setClass("B", representation(b="numeric"), contains="A")
>setClass("C", representation(c="numeric"), contains="B")
>
>setMethod("initialize", signature(.Object="A"),
>          function(.Object, x) {
>              cat("in A\n")
>              [EMAIL PROTECTED] <- x
>              .Object
>          })
>
>setMethod("initialize", signature(.Object="B"),
>          function(.Object, x) {
>              cat("in B\n")
>              .Object <- callNextMethod(.Object=.Object, x=x)
>              [EMAIL PROTECTED] <- [EMAIL PROTECTED] + 1
>              .Object
>          })
>
>setMethod("initialize", signature(.Object="C"),
>          function(.Object, x) {
>              cat("in C\n")
>              .Object <- callNextMethod(.Object=.Object, x=x)
>              [EMAIL PROTECTED] <- [EMAIL PROTECTED] + [EMAIL PROTECTED] + 1
>              .Object
>          })
>
>
>## Works as I am expecting for B
>  
>
>>myB <- new("B", 4)
>>    
>>
>in B
>in A
>
>## When you create a C, the B method gets called but the appropriate
>## next method info seems lost and we end up back in C's method ?!
>  
>
>>myC <- new("C", 5)
>>    
>>
>in C
>in B
>in C
>in B
>in C
>  C-c C-c
>
>Should this work?  Is there a better way to organize the initializers
>for a simple hierarchy (perhaps assume that args to the initializers
>are not the same for A, B, and C).
>
>Thanks,
>
>+ seth
>
>______________________________________________
>R-devel@r-project.org mailing list
>https://stat.ethz.ch/mailman/listinfo/r-devel
>
>  
>

        [[alternative HTML version deleted]]

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to