Package-defined S4 generic covered by a base S3 generic in R packages

May 22, 2013

(This article was first published on Rexamine » Blog/R-bloggers, and kindly contributed to R-bloggers)

While developing our agop package I encountered some problems with calling S4 generic functions defined in the Matrix package, that were created from “base” S3 generics. I don’t know whether it’s an R bug (tested in R 2.15 and R Under development 2013-05-19 3.1-r62765), or whether such behavior was induced intentionally by the R team.

Note that I discuss here package development-related issues, and not the end-user ones.

The scenario was as follows:

  1. I have a package that Depends on the Matrix package.
  2. IN the package I created a function that takes an object of class Matrix (package Matrix) as argument, and calls the S4 generic function (that was my intention) t(); something like:
    test1 <- function(A) {
       stopifnot(is(A, 'Matrix'))
  3. If the function had been created in the global environment, then everything would be OK. In my case, however, I get:
    > x1 <- matrix(1:10, nrow=2)
    > x2 <- Matrix(x1)
    > test1(x2)
    Error in t.default(x) : argument is not a matrix

    Strange, isn't it?

  4. The error message indicates that an S3 method was called here (t.default()). However, in the GlobalEnv, we have:
    > body(t)
    standardGeneric("t") # It's an S4, not S3 generic [defined in the Matrix namespace]

    Quite surprisingly (for me), test1() calls:

    > body(get('t', envir=baseenv()))
    UseMethod("t") # the S3 generic from the BaseEnv

    Why? My package's namespace is ABOVE the Matrix's namespace...

The solution is very simple - call the S4 generic by pointing the Matrix's namespace directly with the :: operator:

test2 <- function(A) {
   stopifnot(is(A, 'Matrix'))

Still, however, I'd like to know WHY we have such behavior - any ideas?

Here is an minimal example of a package exploring this issue: NamespaceTest_0.1.tar.gz (run R CMD INSTALL NamespaceTest_0.1.tar.gz).

@UPDATE: The problem is known (see e.g. this post). Some suggest using importFrom() in the NAMESPACE file. However, the above-given solution, IMHO, is much more elegant and straightforward.

Marek Gągolewski

To leave a comment for the author, please follow the link and comment on their blog: Rexamine » Blog/R-bloggers. offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...

If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

Search R-bloggers


Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)