[R] S4 method dispatch matrixOrArray

Gabor Grothendieck ggrothendieck at gmail.com
Thu Apr 13 13:07:51 CEST 2006


Just run these two (the first example is above the == and the second
after it.  In the first case it gives the expected answer
and in the second case one gets infinite recursion.  The only difference
between the two is the order of the setMethod's:

setGeneric("foo",
          function(A, ...) {
              cat("generic", match.call()[[1]], "\n")
              standardGeneric("foo")
          })

setMethod("foo",
         signature(A = "array"),
         function(A, ...) {
             cat("A =", A, "\n")
         })

setMethod("foo",
         signature(A = "vector"),
         function(A, ...) {
             foo(matrix(A, nrow = 1), ...)
         })

## Test
foo(1:4)
foo(matrix(1:4, 1, 4))
foo(array(1:4, c(1, 4, 1)))

===

setGeneric("foo",
          function(A, ...) {
              cat("generic", match.call()[[1]], "\n")
              standardGeneric("foo")
          })

setMethod("foo",
         signature(A = "vector"),
         function(A, ...) {
             foo(matrix(A, nrow = 1), ...)
         })

setMethod("foo",
         signature(A = "array"),
         function(A, ...) {
             cat("A =", A, "\n")
         })

## Test
foo(1:4)
foo(matrix(1:4, 1, 4))
foo(array(1:4, c(1, 4, 1)))





On 4/13/06, Martin Maechler <maechler at stat.math.ethz.ch> wrote:
> >>>>> "Gabor" == Gabor Grothendieck <ggrothendieck at gmail.com>
> >>>>>     on Wed, 12 Apr 2006 18:24:46 -0400 writes:
>
>    Gabor> This is surprising.  I would have thought that the
>    Gabor> parent/child relationships determine the order that
>    Gabor> dispatched methods are invoked, not the order that
>    Gabor> the setMethod commands are issued in.
>
> My expectations here agree with Gabor's.
> Paul, can you demonstrate your claim,
> namely that the  *order* of the setMethod(.) statements determines
> dispatch behavior ?  I believe that would be faulty.
>
> IIRC, a more "interesting" case of dispatch behavior is the
> one where you have multiple *inheritance*, i.e., have a class
> with more than one superclass ("parent").  If methods for two
> superclasses are defined, some dispatch order has to be
> established, and IIRC some of us have agreed that dispatch order
> for methods should follow "contains order" of the superclasses
> (in the class at hand) -- and I think that's even the case now.
>
> Martin
>
>    Gabor> On 4/12/06, Paul Roebuck <roebuck at mdanderson.org>
>    Gabor> wrote:
>    >> On Wed, 12 Apr 2006, Gabor Grothendieck wrote:
>    >>
>    >> > On 4/12/06, Paul Roebuck <roebuck at mdanderson.org>
>    >> wrote:
>    >> >
>    >> > > I have some code where the primary dispatching is on
>    >> > > other parameters so I'd like not to have to create a
>    >> > > set of functions for "matrix" and another duplicate >
>    >> > set for "array". But the class union technique isn't >
>    >> > working as implemented below and I don't have my Green
>    >> > > book with me. How do I fix my infinite recursion
>    >> problem?
>    >> > >
>    >> > >
>    >> > > ##--------------------------------------------------------
>    >> > > library(methods)
>    >> > >
>    >> > > setGeneric("foo", > > function(A, ...) { > >
>    >> cat("generic", match.call()[[1]], "\n") > >
>    >> standardGeneric("foo") > > })
>    >> > >
>    >> > > setMethod("foo", > > signature(A = "vector"), > >
>    >> function(A, ...) { > > callGeneric(matrix(A, nrow = 1),
>    >> ...)  > > })
>    >> > >
>    >> > > setClassUnion("matrixOrArray", c("matrix", "array"))
>    >> > >
>    >> > > setMethod("foo", > > signature(A = "matrixOrArray"),
>    >> > > function(A, ...) { > > cat("A =", A, "\n") > > })
>    >> > >
>    >> > > ## Test > > foo(1:4) > > foo(matrix(1:4, 1, 4)) > >
>    >> foo(array(1:4, c(1, 4, 1)))
>    >> >
>    >> > I think its good enough to just define an array method,
>    >> i.e. you > don't need the matrix method or the
>    >> matrixOrArray class, and the > vector method can call
>    >> foo(matrix(A,1), ...) so:
>    >> >
>    >> > setGeneric("foo", > function(A, ...) { > cat("generic",
>    >> match.call()[[1]], "\n") > standardGeneric("foo") > })
>    >> >
>    >> > setMethod("foo", > signature(A = "array"), >
>    >> function(A, ...) { > cat("A =", A, "\n") > })
>    >> >
>    >> > setMethod("foo", > signature(A = "vector"), >
>    >> function(A, ...) { > foo(matrix(A, nrow = 1), ...)  > })
>    >>
>    >> Something didn't seem right here. That was pretty close
>    >> to what I had started with, before trying to go the
>    >> classUnion route. Matter of fact, the vector method can
>    >> retain use of callGeneric.
>    >>
>    >> The solution has to do with the order in which calls to
>    >> setMethod are made. Adding foo-vector after foo-array
>    >> works fine; the other way around causes infinite
>    >> recursion.
>    >>
>    >> ----------------------------------------------------------
>    >> SIGSIG -- signature too long (core dumped)
>    >>
>




More information about the R-help mailing list