Debugging unexpected S4 method dispatch

Viewed 86

I am trying to pass an S4 object (sparse matrix of class dgCMatrix from the Matrix package) to a function in another package (Wrench). I am getting some very strange behavior that I am struggling to understand. I suspect it has something to do with S3/S4 method dispatch in R, a subject which I don't really understand.

Example setup:

library(Matrix)
library(Wrench)

M <- Matrix(10 + 1:28, 4, 7)
M[, c(2,4:6)] <- 0
sM <- as(M, "sparseMatrix")
print(sM)
# 4 x 7 sparse Matrix of class "dgCMatrix"
#                     
# [1,] 11 . 19 . . . 35
# [2,] 12 . 20 . . . 36
# [3,] 13 . 21 . . . 37
# [4,] 14 . 22 . . . 38

print(rowSums(sM))
# [1] 65 68 71 74

Next, I call the function, Wrench::wrench to do my analysis:

wrench(sM, colData=c('A','B','A','B','B','A','B'))
# Error in h(simpleError(msg, call)) : 
#   error in evaluating the argument 'i' in selecting a method for function '[': 'x' must be an array of at least two dimensions

Strange... I set a breakpoint on that line in RStudio, step into wrench, it starts like this:

function (mat, condition, etype = "w.marg.mean", ebcf = TRUE, 
  z.adj = FALSE, phi.adj = TRUE, detrend = FALSE, ...) 
{
  mat <- mat[rowSums(mat) > 0, ]
  # ...

Step into that first line, into the call to rowSums(mat), and find myself in base::rowSums.

function (x, na.rm = FALSE, dims = 1L) 
{
  if (is.data.frame(x)) 
    x <- as.matrix(x)
  if (!is.array(x) || length(dn <- dim(x)) < 2L) 
    stop("'x' must be an array of at least two dimensions")

is.data.frame(x) is FALSE, is.array(x) is FALSE, the stop() function is invoked and the error originates from within there. OK, so base::rowSums doesn't know how to handle the sparse matrix and is raising the error...

But why is base::rowSums being invoked when rowSums(mat) is called within wrench, whereas Matrix::rowSums.dgCMatrix is being invoked and everything is working fine when I call rowSums(sM) in the outer scope?

More generally, how do I debug this kind of problem, where method dispatch is not happening as expected (especially within a package that I don't control)?

Other things I have tried:

  • I tried using debugcall, i.e. eval(debugcall(rowSums(sM))) from the outer scope, and it takes me into somewhere in Matrix which calls some C code and ultimately the row sums are printed. When I try the same thing with the debugger paused within Wrench::wrench, I get an error:

    Browse[1]> eval(debugcall(rowSums(mat))) 
    Error in .signatureFromCall(func, mcall, env) :    
    trying to get slot "signature" from an object of a basic class ("function") with no slots
    
  • I have read the S4 chapter of Advanced R several times

0 Answers
Related