[Rd] Redefine NROW and NCOL to be compatible with nrow and ncol for S3 classes with own dim function?

From: Sebastian Kranz <skranz_at_uni-bonn.de>
Date: Sun, 25 Jul 2010 15:04:22 +0200

Dear R-developers,

I am currently trying to develop a package with some customized container classes and found an issue with the functions NROW and NCOL. I guess that I can simply work around the problem by redefining these functions in my own package (Yet, I do not know whether that will work cleanly everywhere). Nevertheless, I thought that perhaps one might think about to redefine these functions in the base package.

As example consider a class that shall behave like a matrix but will be copied by reference rather than by value (may be speed efficient, if a lot of functions manipulate the matrix). This can be done by wrapping the matrix in an environment and writing approbriate methods for dim, "[", etc.

Here an example of some of its code

# An example class that wraps a Matrix in an environment to allow pass by reference
MatrixRef = function(mat) {

   m = new.env(parent=emptyenv())
   class(m) = c("MatrixRef","environment")    m
dim.MatrixRef = function(x) dim(get("mat",envir=x))

# ... define other functions like "[", "[<-", "length" etc.

The functions nrow, ncol, NROW and NCOL are not (internally) generic, i.e. are difficult to overwrite. They rather make use of the generic functions dim (and length).
However, nrow and NROW behave diferently:

> #nrow works but NROW not
> m = MatrixRef(matrix(1:15,5,3))
> dim.MatrixRef(m)

[1] 5 3
> nrow(m) # works

[1] 5
> NROW(m) # Does not work

[1] 1

I feel it is natural that NROW should behave like nrow and deliver dim(x)[1] if the object has a dim attribute.

The reason for the problem is NROW treats special only matrix and data.frame but not every object that has a dim attribute. It is defined as follows in the base package:

function (x) {

     if (is.array(x) || is.data.frame(x)) nrow(x) else length(x) }
<environment: namespace:base>

In my opinion, a good solution would be the following alternative specification:

# Alternative definition of NROW
ALTNROW = function(x) {

   d = dim(x)
   if (!is.null(d)) d[1] else length(x)

Here a check that it works for the Custom Class MatrixRef, as well as, a selection of alternative standard classes:

> vec = runif(10)
> mat = matrix(1:8,4,2)
> df = data.frame(mat)
> li = list("a","b")
> # Everything below works fine

[1] 10
[1] 4
[1] 4
[1] 2

Indeed, it is seems to be even a bit faster than the current specification of NROW:

> speed.NROW = function(R) {

+   for (i in 1:R) {
+     NROW(vec);NROW(mat);NROW(df);NROW(li)
+   }
+ }

> speed.ALTNROW = function(R) {
+   for (i in 1:R) {
+     ALTNROW(vec);ALTNROW(mat);ALTNROW(df);NROW(li)
+   }
+ }

> system.time (speed.NROW(100000))

    user system elapsed
    5.13 0.00 5.26
> system.time (speed.ALTNROW(100000))

    user system elapsed
    3.84 0.00 3.85

For NCOL one could written a similar alternative specification.

Best wishes,

Sebastian Kranz
Department of Economics, University of Bonn

	[[alternative HTML version deleted]]

R-devel_at_r-project.org mailing list
Received on Sun 25 Jul 2010 - 15:27:58 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Sun 25 Jul 2010 - 15:30:19 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive