cdeterman cdeterman - 2 months ago 13
R Question

Export and use S3 method for 'svd'?

I am trying to create an S3 method for the

svd
function applied to a few custom classes. To make things as reproducible as possible I have the following trivial example to demonstrate the problem.

Using
roxygen2
:

# create generic
svd <- function(x, ...) UseMethod("svd")

# add defai;t
svd.default <- base::svd

#' @export
svd.foo <- function(x, ...){
print("called svd.foo")
return(NULL)
}


I then build and reload the package. I can see in the
NAMESPACE
:

S3method(svd,foo)


However, when I try the call I get the following instead of the message:

set.seed(123)
mat <- matrix(rnorm(16), 4)
class(mat) <- "foo"
svd(mat)
$d
[1] 2.5909540 2.2850508 1.2608444 0.1467173

$u
[,1] [,2] [,3] [,4]
[1,] -0.1212454 0.3981507 -0.1101441 0.90257625
[2,] 0.4356515 0.4471180 -0.7466406 -0.22982835
[3,] 0.4227691 -0.7681500 -0.3229738 0.35622984
[4,] -0.7853493 -0.2269518 -0.5710376 -0.07506889

$v
[,1] [,2] [,3] [,4]
[1,] 0.2204894 -0.6736805 -0.2459399 0.66109954
[2,] 0.7409901 0.3288187 -0.5720323 -0.12486370
[3,] 0.0478777 -0.6541094 -0.1526053 -0.73929712
[4,] -0.6324760 0.1008651 -0.7674661 0.02821745


It still calls the base
svd
method. How can I accomplish this?

Answer

You can override non-generic functions by generics, and then provide the required method. So in your case:

#' @export svd
svd = function (x, ...)
    UseMethod('svd')

#' @S3method svd default
svd.default = base::svd

Of course you’d then also add your own method:

#' @S3method svd foo
svd.foo <- function(x, ...) {
  print("called svd.foo")
  return(NULL)
}

As per Hadley, you should not generally @export S3 methods — it’s enough to export the generic, and to mark the methods as @S3methods.