baptiste auguie
2009-Sep-24 20:19 UTC
[Rd] unexpected behavior of `[<-` method for class unit.arithmetic
Dear list, Consider the following, library(grid) w = unit.c(unit(1, "in"), unit(2, "in")) w2 = w + unit(1, "mm") w[2] <- 0 w2[2] <- 0 convertUnit(w, "mm") #[1] 25.4mm 0mm convertUnit(w2, "mm") #Error in grid.Call("L_convert", x, as.integer(whatfrom), as.integer(whatto), : # INTEGER() can only be applied to a 'integer', not a 'NULL' The last line fails, as the naive replacement has destroyed the structure of w2 instead of having assigned a value of 0 to the second unit element. I've also tried, w = unit.c(unit(1, "in"), unit(2, "in")) w2 = w + unit(1, "mm") w2[[2]][2] <- 0 but this time, if the structure is licit, it's the result that's not as I intended: convertUnit(w2,"mm") #[1] 26.4mm 1mm My limited understanding is that an object of class unit.arithmetic is waiting until the last moment to actually perform its operation, stored in a tree-like structure. With this premise, I can't think of a good way to modify one element of a list of unit elements. As a workaround, I can only think of the following hack where the objects are forced to be evaluated, w = unit.c(unit(1, "in"), unit(2, "in")) w2 = convertUnit(w + unit(1, "mm"), "mm", valueOnly=TRUE) w2[2] <- 0 w2 <- unit(w2, "mm") but it clearly isn't a very desirable route. What is the recommended way to modify one element of a unit vector? Digging in grid/R/unit.R , I found the following comment, # Write "[<-.unit" methods too ?? which probably explains the above. Would it be possible to add such a method, "[<-.unit.list" <- function(x, index, value, top=TRUE, ...) { this.length <- length(x) index <- (1L:this.length)[index] if (top && any(index > this.length)) stop("Index out of bounds (unit list subsetting)") cl <- class(x) result <- unclass(x) result[(index - 1) %% this.length + 1] <- value class(result) <- cl result } a = unit.c(unit(1,"mm"),unit(2,"in")) a[2] <- unit(3,"in") a but for unit.arithmetic also? Regards, baptiste sessionInfo() R version 2.9.2 (2009-08-24) i386-apple-darwin8.11.1 locale: en_GB.UTF-8/en_GB.UTF-8/C/C/en_GB.UTF-8/en_GB.UTF-8 attached base packages: [1] stats graphics grDevices utils datasets grid methods [8] base
Paul Murrell
2009-Sep-24 23:39 UTC
[Rd] unexpected behavior of `[<-` method for class unit.arithmetic
Hi The bit you found that says ... # Write "[<-.unit" methods too ?? ... is the crucial bit. Would it be possible to add such a method? Almost certainly, it just needs someone to repeatedly bug the person who can make the change :) Thanks for the suggestion for code BTW; I'll take a look at that. In the meantime, the fact that this has only come up once before, while surprising, suggests that people may have written code in a different style. Can you give a succinct example that demonstrates a situation where you want to assign to a subset of a unit (rather than, say, calculating values, setting some to 0, then building a unit from the values) ? Paul baptiste auguie wrote:> Dear list, > > Consider the following, > > library(grid) > > w = unit.c(unit(1, "in"), unit(2, "in")) > w2 = w + unit(1, "mm") > > w[2] <- 0 > w2[2] <- 0 > > convertUnit(w, "mm") > #[1] 25.4mm 0mm > convertUnit(w2, "mm") > #Error in grid.Call("L_convert", x, as.integer(whatfrom), > as.integer(whatto), : > # INTEGER() can only be applied to a 'integer', not a 'NULL' > > The last line fails, as the naive replacement has destroyed the > structure of w2 instead of having assigned a value of 0 to the second > unit element. > > I've also tried, > > w = unit.c(unit(1, "in"), unit(2, "in")) > w2 = w + unit(1, "mm") > w2[[2]][2] <- 0 > > but this time, if the structure is licit, it's the result that's not > as I intended: > > convertUnit(w2,"mm") > #[1] 26.4mm 1mm > > My limited understanding is that an object of class unit.arithmetic is > waiting until the last moment to actually perform its operation, > stored in a tree-like structure. With this premise, I can't think of a > good way to modify one element of a list of unit elements. > > As a workaround, I can only think of the following hack where the > objects are forced to be evaluated, > > w = unit.c(unit(1, "in"), unit(2, "in")) > w2 = convertUnit(w + unit(1, "mm"), "mm", valueOnly=TRUE) > w2[2] <- 0 > w2 <- unit(w2, "mm") > > but it clearly isn't a very desirable route. > > What is the recommended way to modify one element of a unit vector? > > Digging in grid/R/unit.R , I found the following comment, > > # Write "[<-.unit" methods too ?? > > which probably explains the above. Would it be possible to add such a method, > > "[<-.unit.list" <- function(x, index, value, top=TRUE, ...) { > this.length <- length(x) > index <- (1L:this.length)[index] > > if (top && any(index > this.length)) > stop("Index out of bounds (unit list subsetting)") > cl <- class(x) > result <- unclass(x) > result[(index - 1) %% this.length + 1] <- value > class(result) <- cl > result > } > > a = unit.c(unit(1,"mm"),unit(2,"in")) > a[2] <- unit(3,"in") > a > > but for unit.arithmetic also? > > Regards, > > baptiste > > sessionInfo() > R version 2.9.2 (2009-08-24) > i386-apple-darwin8.11.1 > > locale: > en_GB.UTF-8/en_GB.UTF-8/C/C/en_GB.UTF-8/en_GB.UTF-8 > > attached base packages: > [1] stats graphics grDevices utils datasets grid methods > [8] base > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel-- Dr Paul Murrell Department of Statistics The University of Auckland Private Bag 92019 Auckland New Zealand 64 9 3737599 x85392 paul at stat.auckland.ac.nz http://www.stat.auckland.ac.nz/~paul/