Hadley Wickham
2019-Nov-14 13:47 UTC
[Rd] class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]
On Sun, Nov 10, 2019 at 2:37 AM Martin Maechler <maechler at stat.math.ethz.ch> wrote:> > >>>>> Gabriel Becker > >>>>> on Sat, 2 Nov 2019 12:37:08 -0700 writes: > > > I agree that we can be careful and narrow and still see a > > nice improvement in behavior. While Herve's point is valid > > and I understand his frustration, I think staying within > > the matrix vs c(matrix, array) space is the right scope > > for this work in terms of fiddling with inheritance. > > [.................] > > > > > Also, we seem to have a rule that inherits(x, c) iff c %in% class(x), > > > > good point, and that's why my usage of inherits(.,.) was not > > quite to the point. [OTOH, it was to the point, as indeed from > > the ?class / ?inherits docu, S3 method dispatch and inherits > > must be consistent ] > > > > > which would break -- unless we change class(x) to return the whole > > set of inherited classes, which I sense that we'd rather not do.... > > [................] > > > Note again that both "matrix" and "array" are special [see ?class] as > > being of __implicit class__ and I am considering that this > > implicit class behavior for these two should be slightly > > changed .... > > > > And indeed I think you are right on spot and this would mean > > that indeed the implicit class > > "matrix" should rather become c("matrix", "array"). > > I've made up my mind (and not been contradicted by my fellow R > corers) to try go there for R 4.0.0 next April.I can't seem to find the previous thread, so would you mind being a bit more explicit here? Do you mean adding "array" to the implicit class? Or adding it to the explicit class? Or adding it to inherits? i.e. which of the following results are you proposing to change? is_array <- function(x) UseMethod("is_array") is_array.array <- function(x) TRUE is_array.default <- function(x) FALSE x <- matrix() is_array(x) #> [1] FALSE x <- matrix() inherits(x, "array") #> [1] FALSE class(x) #> [1] "matrix" It would be nice to make sure this is consistent with the behaviour of integers, which have an implicit parent class of numeric: is_numeric <- function(x) UseMethod("is_numeric") is_numeric.numeric <- function(x) TRUE is_numeric.default <- function(x) FALSE x <- 1L is_numeric(x) #> [1] TRUE inherits(x, "numeric") #> [1] FALSE class(x) #> [1] "integer" Hadley -- http://hadley.nz
Pages, Herve
2019-Nov-14 19:13 UTC
[Rd] class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]
On 11/14/19 05:47, Hadley Wickham wrote:> On Sun, Nov 10, 2019 at 2:37 AM Martin Maechler > <maechler at stat.math.ethz.ch> wrote: >> >>>>>>> Gabriel Becker >>>>>>> on Sat, 2 Nov 2019 12:37:08 -0700 writes: >> >> > I agree that we can be careful and narrow and still see a >> > nice improvement in behavior. While Herve's point is valid >> > and I understand his frustration, I think staying within >> > the matrix vs c(matrix, array) space is the right scope >> > for this work in terms of fiddling with inheritance. >> >> [.................] >> >> >>>> Also, we seem to have a rule that inherits(x, c) iff c %in% class(x), >>> >>> good point, and that's why my usage of inherits(.,.) was not >>> quite to the point. [OTOH, it was to the point, as indeed from >>> the ?class / ?inherits docu, S3 method dispatch and inherits >>> must be consistent ] >>> >>> > which would break -- unless we change class(x) to return the whole >>> set of inherited classes, which I sense that we'd rather not do.... >> >> [................] >> >>> Note again that both "matrix" and "array" are special [see ?class] as >>> being of __implicit class__ and I am considering that this >>> implicit class behavior for these two should be slightly >>> changed .... >>> >>> And indeed I think you are right on spot and this would mean >>> that indeed the implicit class >>> "matrix" should rather become c("matrix", "array"). >> >> I've made up my mind (and not been contradicted by my fellow R >> corers) to try go there for R 4.0.0 next April. > > I can't seem to find the previous thread, so would you mind being a > bit more explicit here? Do you mean adding "array" to the implicit > class?It's late in Europe ;-) That's my understanding. I think the plan is to have class(matrix()) return c("matrix", "array"). No class attributes added to matrix or array objects. It's all what is needed to have inherits(matrix(), "array") return TRUE (instead of FALSE at the moment) and S3 dispatch pick up the foo.array method when foo(matrix()) is called and there is no foo.matrix method.> Or adding it to the explicit class? Or adding it to inherits? > i.e. which of the following results are you proposing to change? > > is_array <- function(x) UseMethod("is_array") > is_array.array <- function(x) TRUE > is_array.default <- function(x) FALSE > > x <- matrix() > is_array(x) > #> [1] FALSE > x <- matrix() > inherits(x, "array") > #> [1] FALSE > class(x) > #> [1] "matrix" > > It would be nice to make sure this is consistent with the behaviour of > integers, which have an implicit parent class of numeric:I agree but I don't know if Martin wants to go that far for R 4.0. Hopefully that's the longer term plan though (maybe for R 4.1?). Note that there are other situations that could follow e.g. data.frame/list and probably more... H.> > is_numeric <- function(x) UseMethod("is_numeric") > is_numeric.numeric <- function(x) TRUE > is_numeric.default <- function(x) FALSE > > x <- 1L > is_numeric(x) > #> [1] TRUE > inherits(x, "numeric") > #> [1] FALSE > class(x) > #> [1] "integer" > > Hadley >-- 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
Martin Maechler
2019-Nov-15 16:31 UTC
[Rd] class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]
>>>>> Pages, Herve >>>>> on Thu, 14 Nov 2019 19:13:47 +0000 writes:> On 11/14/19 05:47, Hadley Wickham wrote: >> On Sun, Nov 10, 2019 at 2:37 AM Martin Maechler >> <maechler at stat.math.ethz.ch> wrote: >>> >>>>>>>> Gabriel Becker >>>>>>>> on Sat, 2 Nov 2019 12:37:08 -0700 writes: >>> >>> > I agree that we can be careful and narrow and still see a >>> > nice improvement in behavior. While Herve's point is valid >>> > and I understand his frustration, I think staying within >>> > the matrix vs c(matrix, array) space is the right scope >>> > for this work in terms of fiddling with inheritance. >>> >>> [.................] >>> >>> >>>>> Also, we seem to have a rule that inherits(x, c) iff c %in% class(x), >>>> >>>> good point, and that's why my usage of inherits(.,.) was not >>>> quite to the point. [OTOH, it was to the point, as indeed from >>>> the ?class / ?inherits docu, S3 method dispatch and inherits >>>> must be consistent ] >>>> >>>> > which would break -- unless we change class(x) to return the whole >>>> set of inherited classes, which I sense that we'd rather not do.... >>> >>> [................] >>> >>>> Note again that both "matrix" and "array" are special [see ?class] as >>>> being of __implicit class__ and I am considering that this >>>> implicit class behavior for these two should be slightly >>>> changed .... >>>> >>>> And indeed I think you are right on spot and this would mean >>>> that indeed the implicit class >>>> "matrix" should rather become c("matrix", "array"). >>> >>> I've made up my mind (and not been contradicted by my fellow R >>> corers) to try go there for R 4.0.0 next April. >> >> I can't seem to find the previous thread, so would you mind being a >> bit more explicit here? Do you mean adding "array" to the implicit >> class? > It's late in Europe ;-) > That's my understanding. I think the plan is to have class(matrix()) > return c("matrix", "array"). No class attributes added to matrix or > array objects. > It's all what is needed to have inherits(matrix(), "array") return TRUE > (instead of FALSE at the moment) and S3 dispatch pick up the foo.array > method when foo(matrix()) is called and there is no foo.matrix method. Thank you, Herv?! That's exactly the plan. >> Or adding it to the explicit class? Or adding it to inherits? >> i.e. which of the following results are you proposing to change? >> >> is_array <- function(x) UseMethod("is_array") >> is_array.array <- function(x) TRUE >> is_array.default <- function(x) FALSE >> >> x <- matrix() >> is_array(x) >> #> [1] FALSE >> x <- matrix() >> inherits(x, "array") >> #> [1] FALSE >> class(x) >> #> [1] "matrix" >> >> It would be nice to make sure this is consistent with the behaviour of >> integers, which have an implicit parent class of numeric: > I agree but I don't know if Martin wants to go that far for R 4.0. again, correct. In the mean time, thanks to Tomas Kalibera, my small change has been tested on all of CRAN and Bioc (Software) packages R CMD check <pkg> but no '--as-cran' nor any environment variable settings such as ((strongly recommended by me for package developers !)) _R_CHECK_LENGTH_1_CONDITION_=true _R_CHECK_LENGTH_1_LOGIC2_=verbose>From the package checks, and my own checks I've started noticingonly today, that indeed, the _R_CHECK_LENGTH_1_CONDITION_=true environment variable setting --- stemming more or less directly from an R-devel (mailing list) proposal by Henrik Bengtsson -- and documented in help("if") since R 3.5.0, *together* with the proposal of class(<matrix>) |--> c("matrix", "array") is triggering many new ERRORs because the bad use of class(.) == "..." which I've blogged about is very often inside if(), i.e., if (class(object) == "foobar") # or ` != ` or Now in "new R-devel", and when object is a matrix, if ( class(object) == "foobar") <===> if (c("matrix","array") == "foobar") <===> if (c(FALSE, FALSE)) which is "fine" (i.e, just giving the infamous warning.. which is often surpressed by testthat or similar wrappers) unless you set the env.var .. as I think you R-devel readers all should do : > Sys.unsetenv("_R_CHECK_LENGTH_1_CONDITION_") > if(c(FALSE,FALSE)) 1 else 2 [1] 2 Warning message: In if (c(FALSE, FALSE)) 1 else 2 : the condition has length > 1 and only the first element will be used > Sys.setenv("_R_CHECK_LENGTH_1_CONDITION_" = TRUE) > if(c(FALSE,FALSE)) 1 else 2 Error in if (c(FALSE, FALSE)) 1 else 2 : the condition has length > 1 > > Hopefully that's the longer term plan though (maybe for R 4.1?). I'm not making promises here. Maybe if we could agree to make the equivalent of _R_CHECK_LENGTH_1_CONDITION_=true R 4.0.0's (unconditional?) default behavior, then at least the introduction of class(1L) |--> c("integer", "numeric") would be less problematic because most of the wrong uses of if(class(..) == "integer") would already have been eliminated ... Martin > Note that there are other situations that could follow e.g. > data.frame/list and probably more... > H. >> is_numeric <- function(x) UseMethod("is_numeric") >> is_numeric.numeric <- function(x) TRUE >> is_numeric.default <- function(x) FALSE >> >> x <- 1L >> is_numeric(x) >> #> [1] TRUE >> inherits(x, "numeric") >> #> [1] FALSE >> class(x) >> #> [1] "integer" >> >> Hadley >> > -- > 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
Apparently Analagous Threads
- class(<matrix>) |--> c("matrix", "arrary") -- and S3 dispatch
- class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]
- class(<matrix>) |--> c("matrix", "arrary") -- and S3 dispatch
- class(<matrix>) |--> c("matrix", "arrary") -- and S3 dispatch
- class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]