Hi Abby, Thanks a lot for your paraphrasing and your suggestion! The problem of wrapping the list into a S3/S4 object, i.e. subclassing array or matrix, is that one also has to define a bunch of methods for subsetting, joining, etc, in order to make it behave like a list array. The reason is that most R functions for subsetting, joining, etc. do not preserve class attributes of the input, which is possibly by design. It is not desirable if a simple matrix subsetting will remove the class attributes of the object. There are also many other common functions that are meant to drop the attributes of the input, e.g. lapply, apply -- they are not generics and it is not wise to override them. Overall, introducing a new S3/S4 class often brings some extra price in order to maintain the correct behavior, which is why I tend to avoid them unless it is necessary. Best regards, Jialin On Sunday, July 7, 2019 4:43:59 PM PDT Abby Spurdle wrote:> contains an array of question marks, which > isn't helpful. > > Would it be possible for the print method for both matrices and arrays > (conditional on having a list type), call the format method for each > object, possibly creating a character matrix? > Presumably there are other approaches, but the main thing is that the > output is useful and it's easy for R users to control the way objects (in > matrices and arrays) are printed. > > > Or is there any other place that I can override without introducing a new > > S3 class? > > In theory, the simplest approach is to redefine the print method for > matrices. > However, that would be unacceptable in a CRAN package, probably... > > So, unless R Core change the print method, you may have to create a matrix > subclass.
> The problem of wrapping the list into a S3/S4 object, i.e. subclassingarray> or matrix, is that one also has to define a bunch of methods forsubsetting,> joining, etc, in order to make it behave like a list array.False, sorry. Wrapping != Defining a New Class. And you don't have to define any methods. However, my understanding of your original post is that you want to modify the printing. So, there would only need to be one method, a print method. And if you don't want to do that, you could just create a stand alone custom print function: my.print.function = function (my.matrix.object, quote=FALSE, max.chars=10L) { do.something () }> It is not desirable if a > simple matrix subsetting will remove the class attributes of the object.I'm assuming by "the object" you are referring to the matrix. And by "class attribute"-"s" you are referring to all the attributes. This is a completely separate discussion from your original post. And I don't see what it has to do with printing matrices with a list type. Note that subsetting only removes attributes from the matrix, it does not remove attributes (or slots) from each object in the matrix. Also, note that you may need to use "obj [[i, j]]", with *double* brackets. Because> attributes (obj [i, j])Will be NULL. [[alternative HTML version deleted]]
Hi Abby,> > It is not desirable if a > > simple matrix subsetting will remove the class attributes of the object. > > I'm assuming by "the object" you are referring to the matrix. > And by "class attribute"-"s" you are referring to all the attributes. > This is a completely separate discussion from your original post. > And I don't see what it has to do with printing matrices with a list type.This is what I means: Suppose my list of S4 objects looks like following: myElement <- setClass("myElement", slots = c(x = "integer")) myList <- lapply(1:8, function(x) myElement(x = x)) myArray <- array(myList, c(2,2,2)) myArray # , , 1 # # [,1] [,2] # [1,] ? ? # [2,] ? ? # # , , 2 # # [,1] [,2] # [1,] ? ? # [2,] ? ? Then I want to wrap the list with a new class and defining a new print method for it. class(myArray) <- "myArray" print.myArray <- function(x) { print(`dim<-`(sapply(x, function(x) paste0("'", x at x)), dim(x))) } myArray # , , 1 # # [,1] [,2] # [1,] "'1" "'3" # [2,] "'2" "'4" # # , , 2 # # [,1] [,2] # [1,] "'5" "'7" # [2,] "'6" "'8" This works fine but no longer work after we do some simple operations. myArray[1:2, 1:2, 2] # [,1] [,2] # [1,] ? ? # [2,] ? ? In order to make it work naturally, we have to define the subsetting method. `[.myArray` <- function(x, i, j, ...) { `class<-`(unclass(x)[i, j, ...], class(x)) } myArray[1:2, 1:2, 2] # [,1] [,2] # [1,] "'5" "'7" # [2,] "'6" "'8" And there is a bunch of other methods that needs to be defined for this specific class. This seems too much if I simply want the default list behavior plus printing method. Best regards, Jialin
On 7/7/19 17:41, Jialin Ma wrote:> Hi Abby, > > Thanks a lot for your paraphrasing and your suggestion! > > The problem of wrapping the list into a S3/S4 object, i.e. subclassing array > or matrix, is that one also has to define a bunch of methods for subsetting, > joining, etc, in order to make it behave like a list array. The reason is that > most R functions for subsetting, joining, etc. do not preserve class > attributes of the input, which is possibly by design.Is it? One could argue that a more sensible behavior would be that things like `[`(..., drop=FALSE), rbind(), cbind(), etc... preserve the class attribute. Interestingly t() does that: m <- matrix(1:6, nrow=2) class(m) <- "foo" m # [,1] [,2] [,3] # [1,] 1 3 5 # [2,] 2 4 6 # attr(,"class") # [1] "foo" t(m) # [,1] [,2] # [1,] 1 2 # [2,] 3 4 # [3,] 5 6 # attr(,"class") # [1] "foo" but not aperm() (which in this case would be expected to be equivalent to t()): aperm(m, 2:1) # [,1] [,2] # [1,] 1 2 # [2,] 3 4 # [3,] 5 6 Reshaping also preserves the class: dim(m) <- c(6, 1) m # [,1] # [1,] 1 # [2,] 2 # [3,] 3 # [4,] 4 # [5,] 5 # [6,] 6 # attr(,"class") # [1] "foo" So if it makes sense for t() and reshaping, it's not clear why it wouldn't for [, aperm(), cbind(), etc...? H.> It is not desirable if a > simple matrix subsetting will remove the class attributes of the object. > > There are also many other common functions that are meant to drop the > attributes of the input, e.g. lapply, apply -- they are not generics and it is > not wise to override them. > > Overall, introducing a new S3/S4 class often brings some extra price in order > to maintain the correct behavior, which is why I tend to avoid them unless it > is necessary. > > Best regards, > Jialin > > On Sunday, July 7, 2019 4:43:59 PM PDT Abby Spurdle wrote: >> contains an array of question marks, which >> isn't helpful. >> >> Would it be possible for the print method for both matrices and arrays >> (conditional on having a list type), call the format method for each >> object, possibly creating a character matrix? >> Presumably there are other approaches, but the main thing is that the >> output is useful and it's easy for R users to control the way objects (in >> matrices and arrays) are printed. >> >>> Or is there any other place that I can override without introducing a new >> >> S3 class? >> >> In theory, the simplest approach is to redefine the print method for >> matrices. >> However, that would be unacceptable in a CRAN package, probably... >> >> So, unless R Core change the print method, you may have to create a matrix >> subclass. > > ______________________________________________ > R-devel at r-project.org mailing list > https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_listinfo_r-2Ddevel&d=DwIFAg&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=CFwIFXl8lv7HqmAdD6GKNJ6jlR0VRL1Ek1iGNO_suAk&s=Mhiq-DX7GTrcmqUFXKjuATvQy8Zs6op359DAMvOrois&e>-- Herv? Pag?s Program in Computational Biology Division of Public Health Sciences Fred Hutchinson Cancer Research Center 1100 Fairview Ave. N, M1-B514 P.O. Box 19024 Seattle, WA 98109-1024 E-mail: hpages at fredhutch.org Phone: (206) 667-5791 Fax: (206) 667-1319
Hi Herv?,> Is it? One could argue that a more sensible behavior would be that > things like `[`(..., drop=FALSE), rbind(), cbind(), etc... preserve > the class attribute. > > Interestingly t() does that > > So if it makes sense for t() and reshaping, it's not clear why it > wouldn't for [, aperm(), cbind(), etc...?Thanks for the interesting example and I did not test these functions before. It seems to me that it indeed makes senses to preserve class attributes for these functions -- if there is no specific reason to drop them. And it will make it a lot easier extending the behaviors of base list, matrix and array. Best regards, Jialin On Sunday, July 7, 2019 9:32:29 PM PDT Pages, Herve wrote:> On 7/7/19 17:41, Jialin Ma wrote: > > > Hi Abby, > > > > Thanks a lot for your paraphrasing and your suggestion! > > > > The problem of wrapping the list into a S3/S4 object, i.e. subclassing > > arrayor matrix, is that one also has to define a bunch of methods for> > subsetting, joining, etc, in order to make it behave like a list array. > > The reason is that most R functions for subsetting, joining, etc. do not > > preserve class attributes of the input, which is possibly by design. > > > Is it? One could argue that a more sensible behavior would be that > things like `[`(..., drop=FALSE), rbind(), cbind(), etc... preserve > the class attribute. > > Interestingly t() does that: > > m <- matrix(1:6, nrow=2) > class(m) <- "foo" > > m > # [,1] [,2] [,3] > # [1,] 1 3 5 > # [2,] 2 4 6 > # attr(,"class") > # [1] "foo" > > t(m) > # [,1] [,2] > # [1,] 1 2 > # [2,] 3 4 > # [3,] 5 6 > # attr(,"class") > # [1] "foo" > > but not aperm() (which in this case would be expected to be > equivalent to t()): > > aperm(m, 2:1) > # [,1] [,2] > # [1,] 1 2 > # [2,] 3 4 > # [3,] 5 6 > > Reshaping also preserves the class: > > dim(m) <- c(6, 1) > m > # [,1] > # [1,] 1 > # [2,] 2 > # [3,] 3 > # [4,] 4 > # [5,] 5 > # [6,] 6 > # attr(,"class") > # [1] "foo" > > So if it makes sense for t() and reshaping, it's not clear why it > wouldn't for [, aperm(), cbind(), etc...? > > H. > > > > > It is not desirable if a > > simple matrix subsetting will remove the class attributes of the object. > > > > There are also many other common functions that are meant to drop the > > attributes of the input, e.g. lapply, apply -- they are not generics and > > it isnot wise to override them.> > > > Overall, introducing a new S3/S4 class often brings some extra price in > > orderto maintain the correct behavior, which is why I tend to avoid> > them unless it is necessary. > > > > Best regards, > > Jialin > > > > On Sunday, July 7, 2019 4:43:59 PM PDT Abby Spurdle wrote: > > > >> contains an array of question marks, which > >> isn't helpful. > >> > >> > >> > >> Would it be possible for the print method for both matrices and arrays > >> (conditional on having a list type), call the format method for each > >> object, possibly creating a character matrix? > >> Presumably there are other approaches, but the main thing is that the > >> output is useful and it's easy for R users to control the way objects > >> (in > >> matrices and arrays) are printed. > >> > >> > >> > >>> Or is there any other place that I can override without introducing a > >>> new > >> > >> > >> > >> S3 class? > >> > >> > >> > >> In theory, the simplest approach is to redefine the print method for > >> matrices. > >> However, that would be unacceptable in a CRAN package, probably... > >> > >> > >> > >> So, unless R Core change the print method, you may have to create a > >> matrix > >> subclass. > > > > > > ______________________________________________ > > R-devel at r-project.org mailing list > > https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_ > > listinfo_r-2Ddevel&d=DwIFAg&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_ > > wJYbW0WYiZvSXAJJKaaPhzWA&m=CFwIFXl8lv7HqmAdD6GKNJ6jlR0VRL1Ek1iGNO_suAk&s=M > > hiq-DX7GTrcmqUFXKjuATvQy8Zs6op359DAMvOrois&e > > > -- > Herv? Pag?s > > Program in Computational Biology > Division of Public Health Sciences > Fred Hutchinson Cancer Research Center > 1100 Fairview Ave. N, M1-B514 > P.O. Box 19024 > Seattle, WA 98109-1024 > > E-mail: hpages at fredhutch.org > Phone: (206) 667-5791 > Fax: (206) 667-1319
>>>>> Pages, Herve >>>>> on Mon, 8 Jul 2019 04:32:29 +0000 writes:> On 7/7/19 17:41, Jialin Ma wrote: >> Hi Abby, >> >> Thanks a lot for your paraphrasing and your suggestion! >> >> The problem of wrapping the list into a S3/S4 object, i.e. subclassing array >> or matrix, is that one also has to define a bunch of methods for subsetting, >> joining, etc, in order to make it behave like a list array. The reason is that >> most R functions for subsetting, joining, etc. do not preserve class >> attributes of the input, which is possibly by design. > Is it? One could argue that a more sensible behavior would be that > things like `[`(..., drop=FALSE), rbind(), cbind(), etc... preserve > the class attribute. > Interestingly t() does that: > m <- matrix(1:6, nrow=2) > class(m) <- "foo" > m > # [,1] [,2] [,3] > # [1,] 1 3 5 > # [2,] 2 4 6 > # attr(,"class") > # [1] "foo" > t(m) > # [,1] [,2] > # [1,] 1 2 > # [2,] 3 4 > # [3,] 5 6 > # attr(,"class") > # [1] "foo" > but not aperm() (which in this case would be expected to be > equivalent to t()): > aperm(m, 2:1) > # [,1] [,2] > # [1,] 1 2 > # [2,] 3 4 > # [3,] 5 6 > Reshaping also preserves the class: > dim(m) <- c(6, 1) > m > # [,1] > # [1,] 1 > # [2,] 2 > # [3,] 3 > # [4,] 4 > # [5,] 5 > # [6,] 6 > # attr(,"class") > # [1] "foo" > So if it makes sense for t() and reshaping, it's not clear why it > wouldn't for [, aperm(), cbind(), etc...? > H. I think I definitely tend to agree for aperm(); all others are (slightly or much) more dubious to me however : - `[`: yes probably, but only if drop=FALSE is used, so, e.g. dim & dimnames attributes will be kept {modified to the new dimensions of course} - cbind(), rbind(): Here we are talking about an arbitrary number of arguments, each potentially with different and partly conflicting attributes, notably 'class'. Of course there are -- sometimes quite sophisticated -- S3 and S4 methods that may apply here typically ((notably for specialized matrices, "my" Matrix and Rmpfr packages being mentioned)). For the (internal C code based) default method, a point could be made for trying to keep some attributes of the first argument; but I'm not convinced really yet that it would be wise to change behavior of the (base internal) default method for the cbind() / rbind() twin. >> It is not desirable if a >> simple matrix subsetting will remove the class attributes of the object. The sentence above in its generality is wrong, sorry. Think e.g. of the class "symmetricMatrix", or imagine "covarianceMatrix" or similar: Almost all subsetting will change the most important "property" of the class and keeping the class attribute would be clearly internally inconsistent and wrong. {and also consider that subsetting in R can be with repeated indices, say m[c(1:10, 1:20, 20:1) , ] } >> There are also many other common functions that are meant to drop the >> attributes of the input, e.g. lapply, apply -- they are not generics and it is >> not wise to override them. >> >> Overall, introducing a new S3/S4 class often brings some extra price in order >> to maintain the correct behavior, that is correct >> which is why I tend to avoid them unless it is necessary. well, it is never absolutely necessary, I'd say. { you could tell your users that your objects must only be accessed in one of a few possible ways and all other "access", i.e., function calls with them as arguments is "forbidden" / "undefined" ... .. but your users will not follow what you told them, e.g., if your objects look closely like other R objects they already know very well ... } So, I'm convinced good programmers should pay the extra price _once_ for the benefit of their package useRs and often themselves _forever_ (after that initial price has been paid). Martin >> Best regards, >> Jialin >> >> On Sunday, July 7, 2019 4:43:59 PM PDT Abby Spurdle wrote: >>> contains an array of question marks, which >>> isn't helpful. >>> >>> Would it be possible for the print method for both matrices and arrays >>> (conditional on having a list type), call the format method for each >>> object, possibly creating a character matrix? >>> Presumably there are other approaches, but the main thing is that the >>> output is useful and it's easy for R users to control the way objects (in >>> matrices and arrays) are printed. >>> >>>> Or is there any other place that I can override without introducing a new >>> >>> S3 class? >>> >>> In theory, the simplest approach is to redefine the print method for >>> matrices. >>> However, that would be unacceptable in a CRAN package, probably... >>> >>> So, unless R Core change the print method, you may have to create a matrix >>> subclass. >> >> ______________________________________________ >> R-devel at r-project.org mailing list >> https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_listinfo_r-2Ddevel&d=DwIFAg&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=CFwIFXl8lv7HqmAdD6GKNJ6jlR0VRL1Ek1iGNO_suAk&s=Mhiq-DX7GTrcmqUFXKjuATvQy8Zs6op359DAMvOrois&e >> > -- > Herv? Pag?s > Program in Computational Biology > Division of Public Health Sciences > Fred Hutchinson Cancer Research Center > 1100 Fairview Ave. N, M1-B514 > P.O. Box 19024 > Seattle, WA 98109-1024 > E-mail: hpages at fredhutch.org > Phone: (206) 667-5791 > Fax: (206) 667-1319 > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel