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())
   assign("mat",mat,envir=m)
   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:



 > #THE PROBLEM
 > #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
 > ALTNROW(vec);ALTNROW(mat);ALTNROW(df);NROW(li)
[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

---
Sebastian Kranz
Department of Economics, University of Bonn
http://www.wiwi.uni-bonn.de/kranz/
skranz@uni-bonn.de


	[[alternative HTML version deleted]]

