Can someone help me understand the following behavior of "[<-" ? If I define a simple class based on a matrix, the [<- operation only inserts into the first column:> x <- matrix(rnorm(10),nrow=5,ncol=2) > class(x) <- "foo" > "[<-.foo" <- function(x, i, j, value) {+ if(missing(i)) i <- 1:nrow(x) + if(missing(j)) j <- 1:ncol(x) + + x <- unclass(x) + x <- NextMethod(.Generic) + class(x) <- "foo" + x + }> > x[] <- 100.0 > x[,1] [,2] [1,] 100 -0.1465296 [2,] 100 -0.2615796 [3,] 100 -0.8882629 [4,] 100 -0.2886357 [5,] 100 -0.9565273 attr(,"class") [1] "foo" Based on the behavior of [<- for a matrix, I would have thought that the data for the whole object would be replaced. for instance:> y <- matrix(rnorm(10),nrow=5,ncol=2) > y[,1] [,2] [1,] -0.55297049 -1.1896488 [2,] 0.06157438 -0.6628254 [3,] -0.28184208 -2.5260177 [4,] 0.61204398 -0.3492488 [5,] 0.43971216 1.8990789> y[] <- 100 > y[,1] [,2] [1,] 100 100 [2,] 100 100 [3,] 100 100 [4,] 100 100 [5,] 100 100>Thanks, Whit code for above: x <- matrix(rnorm(10),nrow=5,ncol=2) x class(x) <- "foo" "[<-.foo" <- function(x, i, j, value) { if(missing(i)) i <- 1:nrow(x) if(missing(j)) j <- 1:ncol(x) x <- unclass(x) x <- NextMethod(.Generic) class(x) <- "foo" x } x[] <- 100.0 x> R.Version()$platform [1] "i686-pc-linux-gnu" $arch [1] "i686" $os [1] "linux-gnu" $system [1] "i686, linux-gnu" $status [1] "" $major [1] "2" $minor [1] "3.1" $year [1] "2006" $month [1] "06" $day [1] "01" $`svn rev` [1] "38247" $language [1] "R" $version.string [1] "Version 2.3.1 (2006-06-01)" This e-mail message is intended only for the named recipient(s) above. It may contain confidential information. If you are not the intended recipient you are hereby notified that any dissemination, distribution or copying of this e-mail and any attachment(s) is strictly prohibited. If you have received this e-mail in error, please immediately notify the sender by replying to this e-mail and delete the message and any attachment(s) from your system. Thank you.
Try this: x <- matrix(rnorm(10),nrow=5,ncol=2) class(x) <- "foo" "[<-.foo" <- function(x, i = TRUE, j = TRUE, ..., value) { x <- unclass(x) x <- NextMethod() class(x) <- "foo" x } x[] <- 100.0 On 9/22/06, Armstrong, Whit <whit.armstrong at hcmny.com> wrote:> Can someone help me understand the following behavior of "[<-" ? > > If I define a simple class based on a matrix, the [<- operation only > inserts into the first column: > > > > x <- matrix(rnorm(10),nrow=5,ncol=2) > > class(x) <- "foo" > > "[<-.foo" <- function(x, i, j, value) { > + if(missing(i)) i <- 1:nrow(x) > + if(missing(j)) j <- 1:ncol(x) > + > + x <- unclass(x) > + x <- NextMethod(.Generic) > + class(x) <- "foo" > + x > + } > > > > x[] <- 100.0 > > x > [,1] [,2] > [1,] 100 -0.1465296 > [2,] 100 -0.2615796 > [3,] 100 -0.8882629 > [4,] 100 -0.2886357 > [5,] 100 -0.9565273 > attr(,"class") > [1] "foo" > > Based on the behavior of [<- for a matrix, I would have thought that the > data for the whole object would be replaced. > > for instance: > > > > y <- matrix(rnorm(10),nrow=5,ncol=2) > > y > [,1] [,2] > [1,] -0.55297049 -1.1896488 > [2,] 0.06157438 -0.6628254 > [3,] -0.28184208 -2.5260177 > [4,] 0.61204398 -0.3492488 > [5,] 0.43971216 1.8990789 > > y[] <- 100 > > y > [,1] [,2] > [1,] 100 100 > [2,] 100 100 > [3,] 100 100 > [4,] 100 100 > [5,] 100 100 > > > > > Thanks, > Whit > > > code for above: > > x <- matrix(rnorm(10),nrow=5,ncol=2) > x > class(x) <- "foo" > "[<-.foo" <- function(x, i, j, value) { > if(missing(i)) i <- 1:nrow(x) > if(missing(j)) j <- 1:ncol(x) > x <- unclass(x) > x <- NextMethod(.Generic) > class(x) <- "foo" > x > } > x[] <- 100.0 > x > > > R.Version() > $platform > [1] "i686-pc-linux-gnu" > > $arch > [1] "i686" > > $os > [1] "linux-gnu" > > $system > [1] "i686, linux-gnu" > > $status > [1] "" > > $major > [1] "2" > > $minor > [1] "3.1" > > $year > [1] "2006" > > $month > [1] "06" > > $day > [1] "01" > > $`svn rev` > [1] "38247" > > $language > [1] "R" > > $version.string > [1] "Version 2.3.1 (2006-06-01)" > > > > > This e-mail message is intended only for the named recipient(s) above. It may contain confidential information. If you are not the intended recipient you are hereby notified that any dissemination, distribution or copying of this e-mail and any attachment(s) is strictly prohibited. If you have received this e-mail in error, please immediately notify the sender by replying to this e-mail and delete the message and any attachment(s) from your system. Thank you. > > > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. > > >
I've not seen an actual answer to this, which is that this is a misunderstanding as to how NextMethod works. First,> + x <- unclass(x)looks wrong. NextMethod uses the next method at the call to the generic, and subsequent changes to the object 'x' do not alter the class that would be dispatched on. Given that the next method might not be the default method, unclassing here seems potentially damaging. Second, the matched call is Called from: `[<-.foo`(`*tmp*`, , value = 100) and it is that call which is going to be passed on to the next method. As the help page says: 'NextMethod' works by creating a special call frame for the next method. If no new arguments are supplied, the arguments will be the same in number, order and name as those to the current method but their values will be promises to evaluate their name in the current method and environment. Since 'j' was not an argument of the original call, it is ignored. Now, [<- is an internal generic without a visible default method, but it is as if you have called `[<-.default`(`*tmp*`, 1:5, value = 100), which explains the result you got. (That NextMethod invokes the generic as a possible default method is not documented anywhere that I can see, and the description in 2.3.1 is all about methods invoked via UseMethod. There are issues with the above description when the method invoked is a primitive such as [<-, as that uses positional matching. I would not be confident that this works as intended for multi-argument primitives.) x[,] <- 100 is perhaps what you intended for a matrix-like class, and that does not work (it seems because the argument matching does indeed not work as intended). You need something like `[<-.foo` <- function(x, i, j, value) { if(missing(i)) i <- 1:nrow(x) if(missing(j)) j <- 1:ncol(x) cl <- class(x) cll <- length(cl) m <- match("foo", cl, cll) oldClass(x) <- if(m == cll) NULL else cl[(m+1):cll] x[i,j] <- value class(x) <- cl x } On Fri, 22 Sep 2006, Armstrong, Whit wrote:> Can someone help me understand the following behavior of "[<-" ? > > If I define a simple class based on a matrix, the [<- operation only > inserts into the first column: > > >> x <- matrix(rnorm(10),nrow=5,ncol=2) >> class(x) <- "foo" >> "[<-.foo" <- function(x, i, j, value) { > + if(missing(i)) i <- 1:nrow(x) > + if(missing(j)) j <- 1:ncol(x) > + > + x <- unclass(x) > + x <- NextMethod(.Generic) > + class(x) <- "foo" > + x > + } >> >> x[] <- 100.0 >> x > [,1] [,2] > [1,] 100 -0.1465296 > [2,] 100 -0.2615796 > [3,] 100 -0.8882629 > [4,] 100 -0.2886357 > [5,] 100 -0.9565273 > attr(,"class") > [1] "foo" > > Based on the behavior of [<- for a matrix, I would have thought that the > data for the whole object would be replaced. > > for instance: > >> y <- matrix(rnorm(10),nrow=5,ncol=2) >> y > [,1] [,2] > [1,] -0.55297049 -1.1896488 > [2,] 0.06157438 -0.6628254 > [3,] -0.28184208 -2.5260177 > [4,] 0.61204398 -0.3492488 > [5,] 0.43971216 1.8990789 >> y[] <- 100 >> y > [,1] [,2] > [1,] 100 100 > [2,] 100 100 > [3,] 100 100 > [4,] 100 100 > [5,] 100 100[...] -- Brian D. Ripley, ripley at stats.ox.ac.uk Professor of Applied Statistics, http://www.stats.ox.ac.uk/~ripley/ University of Oxford, Tel: +44 1865 272861 (self) 1 South Parks Road, +44 1865 272866 (PA) Oxford OX1 3TG, UK Fax: +44 1865 272595