From roebuck at mdanderson.org  Tue May  9 21:15:39 2006
From: roebuck at mdanderson.org (Paul Roebuck)
Date: Tue, 9 May 2006 14:15:39 -0500 (CDT)
Subject: [Rd] YA S4 method dispatch question
Message-ID: <Pine.OSF.4.58.0605091347380.485682@wotan.mdacc.tmc.edu>

I recently encountered this and was wondering if someone
could explain what happened. Basis of question involves
what the difference between the calls makes as the end
result is the same:

> identical(matrix(1:8, nrow = 1), array(1:8, c(1, 8)))
TRUE

If I run the code below as shown, I get the following:

> foo(1:8, 4)
foo (vector, numeric)
	 val = 4
foo (matrix, ANY)
	 val = 500
foo (matrix, numeric)
	 val = 500
[1] 500 500 500 500 500 500 500 500

Exchanging the current return for one of the commented ones
(HERE) yields the expected answer:

> foo(1:8, 4)
foo (vector, numeric)
	 val = 4
foo (matrix, numeric)
	 val = 4
[1] 4 4 4 4 4 4 4 4


When invoked with array(), it loses track of the second
parameter and gives the wrong answer. While it would seem
to have something to do with the first parameter's
evaluation time, I don't follow why one works and the other
doesn't. Forcing the evaluation via assignment (third case)
also provides the correct result.

Example code follows:


##------------------------------------------------------------------------------
library(methods)

setGeneric("foo",
           function(x, val = 500) {
               standardGeneric("foo")
           })

setMethod("foo",
          signature(x = "vector", val = "numeric"),
          function(x, val) {
              cat(match.call()[[1]], "(vector, numeric)", "\n")
              cat("\t", "val =", val, "\n")
## HERE ##
#              return(drop(callGeneric(matrix(x, nrow = 1), val)))
              return(drop(callGeneric(array(x, c(1, length(x)), val))))
#              return(drop(callGeneric(xm <- array(x, c(1, length(x))), val)))
          })

setMethod("foo",
          signature(x = "vector"),
          function(x, val) {
              cat(match.call()[[1]], "(vector, ANY)", "\n")
              callGeneric(x, val)
          })

setMethod("foo",
          signature(x = "matrix", val = "numeric"),
          function(x, val) {
              cat(match.call()[[1]], "(matrix, numeric)", "\n")
              cat("\t", "val =", val, "\n")
              return(apply(x, c(1, 2), function(m, v) { m <- v }, val))
          })

setMethod("foo",
          signature(x = "matrix"),
          function(x, val) {
              cat(match.call()[[1]], "(matrix, ANY)", "\n")
              cat("\t", "val =", val, "\n")
              callGeneric(x, val)
          })

setMethod("foo",
          signature(x = "array"),
          function(x, val) {
              cat(match.call()[[1]], "(array, ANY)", "\n")
              stop(sprintf("method not defined for %s argument",
data.class(x)))
          })

setMethod("foo",
          signature(x = "ANY"),
          function(x, val) {
              cat(match.call()[[1]], "(ANY, ANY)", "\n")
              stop(sprintf("method not defined for %s argument",
data.class(x)))
          })

----------------------------------------------------------
SIGSIG -- signature too long (core dumped)



[Rd] YA S4 method dispatch question
Paul Roebuck