head.matrix can return 1000s of columns -- limit to n or add new argument?

classic Classic list List threaded Threaded
46 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: head.matrix can return 1000s of columns -- limit to n or add new argument?

Gabriel Becker-2
Thanks Martin and Peter,

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.

As another point,  I don't know off the top of my head of any other classes
which we would expect to have a dimensions attribute other than arrays
(including the "non-array" 2d matrices) and data.frames, but I imagine
there are some out there.

Do we want the default head and tail methods to be dimension aware as well,
via something along the lines of what I had in my previous message, or do
we want to retain the old behavior for things that aren't data.frames or
matrix/arrays? If the dim attribute can always be assumed to mean the same
thing I feel like it would be nice to give the dimensionality awareness
(and idempotence) to anything with dimensions, but again I don't know much
about the other classes taht have that attribute or how people want to use
them.

It would of course be written in a way that still worked identically to now
for any object that does not have a dimension attribute.

Thoughts?

~G

On Fri, Nov 1, 2019 at 1:52 AM Martin Maechler <[hidden email]>
wrote:

> >>>>> peter dalgaard
> >>>>>     on Thu, 31 Oct 2019 23:04:29 +0100 writes:
>
>     > Hmm, the problem I see here is that these implied classes are all
> inherently one-off. We also have
>     >> inherits(matrix(1,1,1),"numeric")
>     > [1] FALSE
>     >> is.numeric(matrix(1,1,1))
>     > [1] TRUE
>     >> inherits(1L,"numeric")
>     > [1] FALSE
>     >> is.numeric(1L)
>     > [1] TRUE
>
>     > and if we start fixing one, we might need to fix all.
>
> I disagree about "fixing all" (see also my reply to Hervé), and
> the {"numeric","double","integer"} case is particularly messy,
> and I don't want to open that can now.
>
>     > For method dispatch, we do have inheritance, e.g.
>
>     >> foo.numeric <- function(x) x + 1
>     >> foo <- function(x) UseMethod("foo")
>     >> foo(1)
>     > [1] 2
>     >> foo(1L)
>     > [1] 2
>     >> foo(matrix(1,1,1))
>     > [,1]
>     > [1,]    2
>     >> foo.integer <- function(x) x + 2
>     >> foo(1)
>     > [1] 2
>     >> foo(1L)
>     > [1] 3
>     >> foo(matrix(1,1,1))
>     > [,1]
>     > [1,]    2
>     >> foo(matrix(1L,1,1))
>     > [,1]
>     > [1,]    3
>
>     > but these are not all automatic: "integer" implies "numeric", but
> "matrix" does not imply "numeric", much less "integer".
>
> well it should not imply in general:
> Contrary to Math,  we also have 'raw' or 'character' or 'logical' matrices.
>
>
>     > 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....
>
> and we have something like that already with  is(.)
>
> Thank you for these important points raised!
>
> 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
> such that
>
>   foo <- function(x,...) UseMethod("foo")
>   foo.array <- function(x, ...)
>            sprintf("array of dim. %s", paste(dim(x), collapse = " x "))
>
> should work for all arrays and not be an exception for 2D arrays :
>
> > foo(array(pi, 1:3))
> [1] "array of dim. 1 x 2 x 3"
> > foo(array(pi, 1))
> [1] "array of dim. 1"
> > foo(array(pi, 2:7))
> [1] "array of dim. 2 x 3 x 4 x 5 x 6 x 7"
> > foo(array(pi, 1:2))
> Error in UseMethod("foo") :
>   no applicable method for 'foo' applied to an object of class
> "c('matrix', 'double', 'numeric')"
> >
>
> 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").
>
> BTW: The 'Details' section of   ?class   nicely defines things,
>      notably the __implicit class__ situation
>      (but I think should be improved)  :
>
>      {numbering the paragraphs for reference}
>
> > Details:
> >
> > 1.   Here, we describe the so called “S3” classes (and methods). For
> >      “S4” classes (and methods), see ‘Formal classes’ below.
> >
> > 2.   Many R objects have a class attribute, a character vector giving
> >      the names of the classes from which the object _inherits_.
> >      (Functions oldClass and oldClass<- get and set the attribute,
> >      which can also be done directly.)
> >
> > 3.   If the object does not have a class attribute, it has an implicit
> >      class, notably ‘"matrix"’, ‘"array"’, ‘"function"’ or ‘"numeric"’
> >      or the result of ‘typeof(x)’ (which is similar to ‘mode(x)’), but
> >      for type ‘"language"’ and mode ‘"call"’, where the following
> >      extra classes exist for the corresponding function calls: if,
> >      while, for, =, <-, (, {, call.
>
> So, I think clearly  { for S3, not S4 ! }
>
>   "class attribute" :=  attr(x, "class")
>
>   "implicit class" := the class(x) of R objects that do *not*
>                       have a class attribute
>
>
> > 4.   Note that NULL objects cannot have attributes (hence not
> >      classes) and attempting to assign a class is an error.
>
> the above has one small flaw : "(hence not classes)" is not correct.
> Of course   class(NULL) is "NULL" by par. 3's  typeof(x) "rule".
>
> > 5a.  When a generic function ‘fun’ is applied to an object with class
> >      attribute ‘c("first", "second")’, the system searches for a
> >      function called ‘fun.first’ and, if it finds it, applies it to the
> >      object.  If no such function is found, a function called
> >      ‘fun.second’ is tried.  If no class name produces a suitable
> >      function, the function ‘fun.default’ is used (if it exists).
> > 5b.  If there is no class attribute, the implicit class is tried, then
> the
> >      default method.
>
> > 6.   The function 'class' prints the vector of names of classes an
> >      object inherits from.  Correspondingly, class<- sets the classes
> >      an object inherits from.  Assigning NULL removes the class
> >      attribute.
>
> ["of course", the word  "prints" above should be replaced by "returns" ! ]
>
> > 7.   'unclass' returns (a copy of) its argument with its class
> >      attribute removed.  (It is not allowed for objects which cannot be
> >      copied, namely environments and external pointers.)
>
> > 8.   'inherits' indicates whether its first argument inherits from any
> >      of the classes specified in the ‘what’ argument.  If which is
> >      TRUE then an integer vector of the same length as ‘what’ is
> >      returned.  Each element indicates the position in the ‘class(x)’
> >      matched by the element of ‘what’; zero indicates no match. If
> >      which is FALSE then TRUE is returned by inherits if any of
> >      the names in ‘what’ match with any class.
>
> {I had forgotten that the 2nd argument of inherits, 'what', can
>  be a vector and about the 'which' argument}
>
>
>     >> On 30 Oct 2019, at 12:29 , Martin Maechler <
> [hidden email]> wrote:
>     >>
>     >> Note however the following  historical quirk :
>     >>
>     >>> sapply(setNames(,1:5), function(K) inherits(array(pi, dim=1:K),
> "array"))
>     >> 1     2     3     4     5
>     >> TRUE FALSE  TRUE  TRUE  TRUE
>     >>
>     >> (Is this something we should consider changing for R 4.0.0 -- to
>     >> have it TRUE also for 2d-arrays aka matrix objects ??)
>
>     > --
>     > Peter Dalgaard, Professor,
>     > Center for Statistics, Copenhagen Business School
>     > Solbjerg Plads 3, 2000 Frederiksberg, Denmark
>     > Phone: (+45)38153501
>     > Office: A 4.23
>     > Email: [hidden email]  Priv: [hidden email]
>
>
>
>
>
>
>
>
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: head.matrix can return 1000s of columns -- limit to n or add new argument?

Gabriel Becker-2
As I hit send I realized I did know of one, which is table objects. So
while we're discussing it we can talk about both generally and specifically
what head.table and tail.table should do. Looks like tail.table is already
special -cased to hit the matrix method if it is 2d, so the natural
extension of that would be hitting tail.array for any 2+d table, I think.

~G

On Sat, Nov 2, 2019 at 12:37 PM Gabriel Becker <[hidden email]>
wrote:

> Thanks Martin and Peter,
>
> 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.
>
> As another point,  I don't know off the top of my head of any other
> classes which we would expect to have a dimensions attribute other than
> arrays (including the "non-array" 2d matrices) and data.frames, but I
> imagine there are some out there.
>
> Do we want the default head and tail methods to be dimension aware as
> well, via something along the lines of what I had in my previous message,
> or do we want to retain the old behavior for things that aren't data.frames
> or matrix/arrays? If the dim attribute can always be assumed to mean the
> same thing I feel like it would be nice to give the dimensionality
> awareness (and idempotence) to anything with dimensions, but again I don't
> know much about the other classes taht have that attribute or how people
> want to use them.
>
> It would of course be written in a way that still worked identically to
> now for any object that does not have a dimension attribute.
>
> Thoughts?
>
> ~G
>
> On Fri, Nov 1, 2019 at 1:52 AM Martin Maechler <[hidden email]>
> wrote:
>
>> >>>>> peter dalgaard
>> >>>>>     on Thu, 31 Oct 2019 23:04:29 +0100 writes:
>>
>>     > Hmm, the problem I see here is that these implied classes are all
>> inherently one-off. We also have
>>     >> inherits(matrix(1,1,1),"numeric")
>>     > [1] FALSE
>>     >> is.numeric(matrix(1,1,1))
>>     > [1] TRUE
>>     >> inherits(1L,"numeric")
>>     > [1] FALSE
>>     >> is.numeric(1L)
>>     > [1] TRUE
>>
>>     > and if we start fixing one, we might need to fix all.
>>
>> I disagree about "fixing all" (see also my reply to Hervé), and
>> the {"numeric","double","integer"} case is particularly messy,
>> and I don't want to open that can now.
>>
>>     > For method dispatch, we do have inheritance, e.g.
>>
>>     >> foo.numeric <- function(x) x + 1
>>     >> foo <- function(x) UseMethod("foo")
>>     >> foo(1)
>>     > [1] 2
>>     >> foo(1L)
>>     > [1] 2
>>     >> foo(matrix(1,1,1))
>>     > [,1]
>>     > [1,]    2
>>     >> foo.integer <- function(x) x + 2
>>     >> foo(1)
>>     > [1] 2
>>     >> foo(1L)
>>     > [1] 3
>>     >> foo(matrix(1,1,1))
>>     > [,1]
>>     > [1,]    2
>>     >> foo(matrix(1L,1,1))
>>     > [,1]
>>     > [1,]    3
>>
>>     > but these are not all automatic: "integer" implies "numeric", but
>> "matrix" does not imply "numeric", much less "integer".
>>
>> well it should not imply in general:
>> Contrary to Math,  we also have 'raw' or 'character' or 'logical'
>> matrices.
>>
>>
>>     > 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....
>>
>> and we have something like that already with  is(.)
>>
>> Thank you for these important points raised!
>>
>> 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
>> such that
>>
>>   foo <- function(x,...) UseMethod("foo")
>>   foo.array <- function(x, ...)
>>            sprintf("array of dim. %s", paste(dim(x), collapse = " x "))
>>
>> should work for all arrays and not be an exception for 2D arrays :
>>
>> > foo(array(pi, 1:3))
>> [1] "array of dim. 1 x 2 x 3"
>> > foo(array(pi, 1))
>> [1] "array of dim. 1"
>> > foo(array(pi, 2:7))
>> [1] "array of dim. 2 x 3 x 4 x 5 x 6 x 7"
>> > foo(array(pi, 1:2))
>> Error in UseMethod("foo") :
>>   no applicable method for 'foo' applied to an object of class
>> "c('matrix', 'double', 'numeric')"
>> >
>>
>> 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").
>>
>> BTW: The 'Details' section of   ?class   nicely defines things,
>>      notably the __implicit class__ situation
>>      (but I think should be improved)  :
>>
>>      {numbering the paragraphs for reference}
>>
>> > Details:
>> >
>> > 1.   Here, we describe the so called “S3” classes (and methods). For
>> >      “S4” classes (and methods), see ‘Formal classes’ below.
>> >
>> > 2.   Many R objects have a class attribute, a character vector giving
>> >      the names of the classes from which the object _inherits_.
>> >      (Functions oldClass and oldClass<- get and set the attribute,
>> >      which can also be done directly.)
>> >
>> > 3.   If the object does not have a class attribute, it has an implicit
>> >      class, notably ‘"matrix"’, ‘"array"’, ‘"function"’ or ‘"numeric"’
>> >      or the result of ‘typeof(x)’ (which is similar to ‘mode(x)’), but
>> >      for type ‘"language"’ and mode ‘"call"’, where the following
>> >      extra classes exist for the corresponding function calls: if,
>> >      while, for, =, <-, (, {, call.
>>
>> So, I think clearly  { for S3, not S4 ! }
>>
>>   "class attribute" :=  attr(x, "class")
>>
>>   "implicit class" := the class(x) of R objects that do *not*
>>                       have a class attribute
>>
>>
>> > 4.   Note that NULL objects cannot have attributes (hence not
>> >      classes) and attempting to assign a class is an error.
>>
>> the above has one small flaw : "(hence not classes)" is not correct.
>> Of course   class(NULL) is "NULL" by par. 3's  typeof(x) "rule".
>>
>> > 5a.  When a generic function ‘fun’ is applied to an object with class
>> >      attribute ‘c("first", "second")’, the system searches for a
>> >      function called ‘fun.first’ and, if it finds it, applies it to the
>> >      object.  If no such function is found, a function called
>> >      ‘fun.second’ is tried.  If no class name produces a suitable
>> >      function, the function ‘fun.default’ is used (if it exists).
>> > 5b.  If there is no class attribute, the implicit class is tried, then
>> the
>> >      default method.
>>
>> > 6.   The function 'class' prints the vector of names of classes an
>> >      object inherits from.  Correspondingly, class<- sets the classes
>> >      an object inherits from.  Assigning NULL removes the class
>> >      attribute.
>>
>> ["of course", the word  "prints" above should be replaced by "returns" ! ]
>>
>> > 7.   'unclass' returns (a copy of) its argument with its class
>> >      attribute removed.  (It is not allowed for objects which cannot be
>> >      copied, namely environments and external pointers.)
>>
>> > 8.   'inherits' indicates whether its first argument inherits from any
>> >      of the classes specified in the ‘what’ argument.  If which is
>> >      TRUE then an integer vector of the same length as ‘what’ is
>> >      returned.  Each element indicates the position in the ‘class(x)’
>> >      matched by the element of ‘what’; zero indicates no match. If
>> >      which is FALSE then TRUE is returned by inherits if any of
>> >      the names in ‘what’ match with any class.
>>
>> {I had forgotten that the 2nd argument of inherits, 'what', can
>>  be a vector and about the 'which' argument}
>>
>>
>>     >> On 30 Oct 2019, at 12:29 , Martin Maechler <
>> [hidden email]> wrote:
>>     >>
>>     >> Note however the following  historical quirk :
>>     >>
>>     >>> sapply(setNames(,1:5), function(K) inherits(array(pi, dim=1:K),
>> "array"))
>>     >> 1     2     3     4     5
>>     >> TRUE FALSE  TRUE  TRUE  TRUE
>>     >>
>>     >> (Is this something we should consider changing for R 4.0.0 -- to
>>     >> have it TRUE also for 2d-arrays aka matrix objects ??)
>>
>>     > --
>>     > Peter Dalgaard, Professor,
>>     > Center for Statistics, Copenhagen Business School
>>     > Solbjerg Plads 3, 2000 Frederiksberg, Denmark
>>     > Phone: (+45)38153501
>>     > Office: A 4.23
>>     > Email: [hidden email]  Priv: [hidden email]
>>
>>
>>
>>
>>
>>
>>
>>
>>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Martin Maechler
In reply to this post by Gabriel Becker-2
>>>>> 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've found the few places in base R that needed a change (to
pass 'make check-all' in the R sources) and found that indeed a
overzealous check in 'Matrix' needed also a change (a place
where the checking code assume  class(<matrix>) |--> "matrix" ).

There are certainly many more package (codes and checks) that
need adaption .. i.e., should be changed rather *before* the
above change is activated in R-devel (and then will affect all CRAN
and Bioconductor checks.)

To this end, I've published an  'R Blog' yesterday,

   http://bit.ly/R_blog_class_think_2x

which translates to

   https://developer.r-project.org/Blog/public/2019/11/09/when-you-think-class.-think-again/index.html

notably mentioning why using  class(x) == "...."  (or '!=')  or
switch(class(.) ...)  is quite unsafe and hence bad and you
should very often not replace  class(x)  by  class(x)[1]  but
really use the "only truly correct" ;-)

     inherits(x,  "...")
or
     is(x,  "....")   # if you're advanced/brave enough (:-) to
               # use formal classes (S4)
     
Martin Maechler
ETH Zurich and R Core Team

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Bryan Hanson


> On Nov 10, 2019, at 3:36 AM, Martin Maechler <[hidden email]> 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've found the few places in base R that needed a change (to
> pass 'make check-all' in the R sources) and found that indeed a
> overzealous check in 'Matrix' needed also a change (a place
> where the checking code assume  class(<matrix>) |--> "matrix" ).
>
> There are certainly many more package (codes and checks) that
> need adaption .. i.e., should be changed rather *before* the
> above change is activated in R-devel (and then will affect all CRAN
> and Bioconductor checks.)
>
> To this end, I've published an  'R Blog' yesterday,
>
>   http://bit.ly/R_blog_class_think_2x
>
> which translates to
>
>   https://developer.r-project.org/Blog/public/2019/11/09/when-you-think-class.-think-again/index.html
>
> notably mentioning why using  class(x) == "...."  (or '!=')  or
> switch(class(.) ...)  is quite unsafe and hence bad and you
> should very often not replace  class(x)  by  class(x)[1]  but
> really use the "only truly correct" ;-)
>
>     inherits(x,  "...")
> or
>     is(x,  "....")   # if you're advanced/brave enough (:-) to
>              # use formal classes (S4)

Thanks for the helpful blog post Martin. Is the following

  “test_class”  %in% class(some_object)

which I think in your symbols would be

  “…” %in% class(x)

safe as far as you see it? By safe, I mean equivalent to your suggestion of inherits(x, “…”) .

Thanks, Bryan

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Duncan Murdoch-2
On 10/11/2019 9:17 a.m., Bryan Hanson wrote:

>
>
>> On Nov 10, 2019, at 3:36 AM, Martin Maechler <[hidden email]> 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've found the few places in base R that needed a change (to
>> pass 'make check-all' in the R sources) and found that indeed a
>> overzealous check in 'Matrix' needed also a change (a place
>> where the checking code assume  class(<matrix>) |--> "matrix" ).
>>
>> There are certainly many more package (codes and checks) that
>> need adaption .. i.e., should be changed rather *before* the
>> above change is activated in R-devel (and then will affect all CRAN
>> and Bioconductor checks.)
>>
>> To this end, I've published an  'R Blog' yesterday,
>>
>>    http://bit.ly/R_blog_class_think_2x
>>
>> which translates to
>>
>>    https://developer.r-project.org/Blog/public/2019/11/09/when-you-think-class.-think-again/index.html
>>
>> notably mentioning why using  class(x) == "...."  (or '!=')  or
>> switch(class(.) ...)  is quite unsafe and hence bad and you
>> should very often not replace  class(x)  by  class(x)[1]  but
>> really use the "only truly correct" ;-)
>>
>>      inherits(x,  "...")
>> or
>>      is(x,  "....")   # if you're advanced/brave enough (:-) to
>>                # use formal classes (S4)
>
> Thanks for the helpful blog post Martin. Is the following
>
>    “test_class”  %in% class(some_object)
>
> which I think in your symbols would be
>
>    “…” %in% class(x)
>
> safe as far as you see it? By safe, I mean equivalent to your suggestion of inherits(x, “…”) .

Those aren't equivalent if S4 gets involved.  You can see it if you run
this code:

example("new") # Creates an object named t2 of class "trackcurve"
                # that contains "track"
inherits(t2, "track")  # TRUE
"track" %in% class(t2) # FALSE

I can't think of any examples not involving S4.

Duncan Murdoch

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Martin Maechler
>>>>> Duncan Murdoch
>>>>>     on Sun, 10 Nov 2019 11:48:26 -0500 writes:

    > On 10/11/2019 9:17 a.m., Bryan Hanson wrote:
    >>
    >>
    >>> On Nov 10, 2019, at 3:36 AM, Martin Maechler <[hidden email]> 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've found the few places in base R that needed a change (to
    >>> pass 'make check-all' in the R sources) and found that indeed a
    >>> overzealous check in 'Matrix' needed also a change (a place
    >>> where the checking code assume  class(<matrix>) |--> "matrix" ).
    >>>
    >>> There are certainly many more package (codes and checks) that
    >>> need adaption .. i.e., should be changed rather *before* the
    >>> above change is activated in R-devel (and then will affect all CRAN
    >>> and Bioconductor checks.)
    >>>
    >>> To this end, I've published an  'R Blog' yesterday,
    >>>
    >>> http://bit.ly/R_blog_class_think_2x
    >>>
    >>> which translates to
    >>>
    >>> https://developer.r-project.org/Blog/public/2019/11/09/when-you-think-class.-think-again/index.html
    >>>
    >>> notably mentioning why using  class(x) == "...."  (or '!=')  or
    >>> switch(class(.) ...)  is quite unsafe and hence bad and you
    >>> should very often not replace  class(x)  by  class(x)[1]  but
    >>> really use the "only truly correct" ;-)
    >>>
    >>> inherits(x,  "...")
    >>> or
    >>> is(x,  "....")   # if you're advanced/brave enough (:-) to
    >>> # use formal classes (S4)
    >>
    >> Thanks for the helpful blog post Martin. Is the following
    >>
    >> “test_class”  %in% class(some_object)
    >>
    >> which I think in your symbols would be
    >>
    >> “…” %in% class(x)
    >>
    >> safe as far as you see it? By safe, I mean equivalent to your suggestion of inherits(x, “…”) .

    > Those aren't equivalent if S4 gets involved.  You can see it if you run
    > this code:

    > example("new") # Creates an object named t2 of class "trackcurve"
    >                # that contains "track"

    > inherits(t2, "track")  # TRUE
    > "track" %in% class(t2) # FALSE

    > I can't think of any examples not involving S4.

    > Duncan Murdoch

Thank you, Duncan.
That's definitely a strong reason for inherits(), because often
in such code, you don't know in advance what objects will be
passed to your function.


On Twitter, others have asked "the same",  arguing that

        "<someclass>"  %in%  class(.)

> uses usual syntax, and thus looks less intimidating than
> inherit() and less cryptic than is()

I think you should all use -- and *teach* --
inherits(.) more often, and it would no longer be intimidating.

Also, for the speed fetishists:  inherits() will typically be
slightly (but significantly) faster than  ` %in% class(.) `

Martin

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Hervé Pagès-2


On 11/11/19 01:40, Martin Maechler wrote:

>>>>>> Duncan Murdoch
>>>>>>      on Sun, 10 Nov 2019 11:48:26 -0500 writes:
>
>      > On 10/11/2019 9:17 a.m., Bryan Hanson wrote:
>      >>
>      >>
>      >>> On Nov 10, 2019, at 3:36 AM, Martin Maechler <[hidden email]> 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've found the few places in base R that needed a change (to
>      >>> pass 'make check-all' in the R sources) and found that indeed a
>      >>> overzealous check in 'Matrix' needed also a change (a place
>      >>> where the checking code assume  class(<matrix>) |--> "matrix" ).
>      >>>
>      >>> There are certainly many more package (codes and checks) that
>      >>> need adaption .. i.e., should be changed rather *before* the
>      >>> above change is activated in R-devel (and then will affect all CRAN
>      >>> and Bioconductor checks.)
>      >>>
>      >>> To this end, I've published an  'R Blog' yesterday,
>      >>>
>      >>> https://urldefense.proofpoint.com/v2/url?u=http-3A__bit.ly_R-5Fblog-5Fclass-5Fthink-5F2x&d=DwIDaQ&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=Haem9CPNVAwtpdrnFb50tn-RoEohzBVpzJRgkjRFqBg&s=TFCIJjbe482LLMV-P2B9vTc5G8nIcW0Ekx25qhuzCOg&e=
>      >>>
>      >>> which translates to
>      >>>
>      >>> https://urldefense.proofpoint.com/v2/url?u=https-3A__developer.r-2Dproject.org_Blog_public_2019_11_09_when-2Dyou-2Dthink-2Dclass.-2Dthink-2Dagain_index.html&d=DwIDaQ&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=Haem9CPNVAwtpdrnFb50tn-RoEohzBVpzJRgkjRFqBg&s=kbZV1cxdT0uFW2gX8iCQmV-SANS8xCp678it1okCRqs&e=
>      >>>
>      >>> notably mentioning why using  class(x) == "...."  (or '!=')  or
>      >>> switch(class(.) ...)  is quite unsafe and hence bad and you
>      >>> should very often not replace  class(x)  by  class(x)[1]  but
>      >>> really use the "only truly correct" ;-)
>      >>>
>      >>> inherits(x,  "...")
>      >>> or
>      >>> is(x,  "....")   # if you're advanced/brave enough (:-) to
>      >>> # use formal classes (S4)
>      >>
>      >> Thanks for the helpful blog post Martin. Is the following
>      >>
>      >> “test_class”  %in% class(some_object)
>      >>
>      >> which I think in your symbols would be
>      >>
>      >> “…” %in% class(x)
>      >>
>      >> safe as far as you see it? By safe, I mean equivalent to your suggestion of inherits(x, “…”) .
>
>      > Those aren't equivalent if S4 gets involved.  You can see it if you run
>      > this code:
>
>      > example("new") # Creates an object named t2 of class "trackcurve"
>      >                # that contains "track"
>
>      > inherits(t2, "track")  # TRUE
>      > "track" %in% class(t2) # FALSE
>
>      > I can't think of any examples not involving S4.
>
>      > Duncan Murdoch
>
> Thank you, Duncan.
> That's definitely a strong reason for inherits(), because often
> in such code, you don't know in advance what objects will be
> passed to your function.
>
>
> On Twitter, others have asked "the same",  arguing that
>
> "<someclass>"  %in%  class(.)
>
>> uses usual syntax, and thus looks less intimidating than
>> inherit() and less cryptic than is()

%-/  (<- ASCII version of the rolling eyes emoji)

<ranting mode>

The most cryptic of the 3 forms being by far:

    "<someclass>" %in% class(x)

You need to be able to read thru this to understand that the intend is
to find out whether 'x' belongs to class "<someclass>" or to one of its
subclasses. What could be more natural and readable than using
inherits(x, "<someclass>") for that? What's unusual or intimidating
about its syntax?

OK I could see that maybe some people would like to be able to use a
binary operator instead of a function call for this (a la instanceof in
Java):

   `%inherits%` <- inherits

   library(data.table)

   x <- data.table()
   x %inherits% "data.frame"
   [1] TRUE

which would be a reasonable request (looks cute).

But trying to make the case for "<someclass>" %in% class(x) on
Twitter??!  %-/

</ranting mode>

H.


>
> I think you should all use -- and *teach* --
> inherits(.) more often, and it would no longer be intimidating.
>
> Also, for the speed fetishists:  inherits() will typically be
> slightly (but significantly) faster than  ` %in% class(.) `
>
> Martin
>
> ______________________________________________
> [hidden email] mailing list
> https://urldefense.proofpoint.com/v2/url?u=https-3A__stat.ethz.ch_mailman_listinfo_r-2Ddevel&d=DwIDaQ&c=eRAMFD45gAfqt84VtBcfhQ&r=BK7q3XeAvimeWdGbWY_wJYbW0WYiZvSXAJJKaaPhzWA&m=Haem9CPNVAwtpdrnFb50tn-RoEohzBVpzJRgkjRFqBg&s=leJubS1ZTBLker3GGD9hOhoXb4NCoydeg_wIUDg8cHs&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: [hidden email]
Phone:  (206) 667-5791
Fax:    (206) 667-1319
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Abby Spurdle
<polite mode>

>    x %inherits% "data.frame"

IMHO, I think that user-defined binary operators are being over-used
within the R community.

I don't think that they're "cute" or stylish.
I think their use should be limited to cases, where they significantly
increase the readability of the code.

However, readability, is a (partly) subjective topic...

</pilote mode>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Hervé Pagès-2
On 11/12/19 12:21, Abby Spurdle wrote:

> <polite mode>
>
>>     x %inherits% "data.frame"
>
> IMHO, I think that user-defined binary operators are being over-used
> within the R community.
>
> I don't think that they're "cute" or stylish.
> I think their use should be limited to cases, where they significantly
> increase the readability of the code.
>
> However, readability, is a (partly) subjective topic...
>
> </pilote mode>
>

You can have your own rant about "user-defined binary operators being
over-used within the R community" without suggesting that my rant was
rude. I don't think it was and, in any case, I was not going after a
individual in particular. Contrary to popular belief and to what I tell
my daughter, rolling your eyes in public is not rude at all and is
actually a lot of fun. You should try it ;-)


--
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: [hidden email]
Phone:  (206) 667-5791
Fax:    (206) 667-1319
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Abby Spurdle
> You can have your own rant about "user-defined binary operators being
> over-used within the R community" without suggesting that my rant was
> rude.

I wasn't suggesting that you were rude.
I was questioning a trend.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Hervé Pagès-2
On 11/12/19 14:03, Abby Spurdle wrote:
>> You can have your own rant about "user-defined binary operators being
>> over-used within the R community" without suggesting that my rant was
>> rude.
>
> I wasn't suggesting that you were rude.
> I was questioning a trend.

ok, well, I must ave misinterpreted the <polite> </polite> markup you've
put around your rant then...

Have a nice day,
H.

--
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: [hidden email]
Phone:  (206) 667-5791
Fax:    (206) 667-1319
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

hadley wickham
In reply to this post by Martin Maechler
On Sun, Nov 10, 2019 at 2:37 AM Martin Maechler
<[hidden email]> 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

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Hervé Pagès-2


On 11/14/19 05:47, Hadley Wickham wrote:

> On Sun, Nov 10, 2019 at 2:37 AM Martin Maechler
> <[hidden email]> 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: [hidden email]
Phone:  (206) 667-5791
Fax:    (206) 667-1319
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Martin Maechler
>>>>> 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
    >> <[hidden email]> 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 noticing
only 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: [hidden email]
    > Phone:  (206) 667-5791
    > Fax:    (206) 667-1319

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

_R_CHECK_LENGTH_1_LOGIC2_ setting and Rstudio ..

Martin Maechler
>>>>> Martin Maechler
>>>>>     on Fri, 15 Nov 2019 17:31:15 +0100 writes:

    > as ((strongly recommended by me for package developers !))

    > _R_CHECK_LENGTH_1_CONDITION_=true
    > _R_CHECK_LENGTH_1_LOGIC2_=verbose

Apropos, for many months now, when very occasionally using
Rstudio (notably for teaching to beginners),
I've needed to use a wrapper shell script *unsetting* these,
because otherwise I've got "a bomb" from trying to run Rstudio,
as it internally uses code that fails when
 _R_CHECK_LENGTH_1_LOGIC2_
is activated, see the screen shot (from the very latest
Rstudio 1.2.5019),
at least in my case where I use a non-trival  'options(repos = ..)'
in my startup.


______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

rstudio_killed_by_R_CHECK_screenshot.png (85K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: _R_CHECK_LENGTH_1_LOGIC2_ setting and Rstudio ..

Henrik Bengtsson-5
Yes, I ran into this too. I think they fixed it for RStudio 1.3
(https://github.com/rstudio/rstudio/pull/5457/files).  My workaround
is to enable these checks conditionally on not running R in the
RStudio Console (it works in the RStudio Terminal).  To test for the
RStudio Console, you need to turn to .Rprofile rather than .Renviron,
e.g.

## Strict run-time checks, unless in the RStudio Console
if (Sys.getenv("RSTUDIO") != "1" || nzchar(Sys.getenv("RSTUDIO_TERM")) {
  Sys.setenv(
    "_R_CHECK_LENGTH_1_CONDITION_" = "true",
    "_R_CHECK_LENGTH_1_LOGIC2_" = "verbose"
  )
}

FWIW, for those who use 'startup::startup()` in ~/.Rprofile, the above
can also be done by having a file named (exactly)
'.Renviron.d/strict,rstudio=FALSE' containing:

_R_CHECK_LENGTH_1_CONDITION_=true
_R_CHECK_LENGTH_1_LOGIC2_=verbose

startup() will only process this file when R is *not* running in the
RStudio Console (`rstudio=FALSE`).

/Henrik

On Fri, Nov 15, 2019 at 9:00 AM Martin Maechler
<[hidden email]> wrote:

>
> >>>>> Martin Maechler
> >>>>>     on Fri, 15 Nov 2019 17:31:15 +0100 writes:
>
>     > as ((strongly recommended by me for package developers !))
>
>     > _R_CHECK_LENGTH_1_CONDITION_=true
>     > _R_CHECK_LENGTH_1_LOGIC2_=verbose
>
> Apropos, for many months now, when very occasionally using
> Rstudio (notably for teaching to beginners),
> I've needed to use a wrapper shell script *unsetting* these,
> because otherwise I've got "a bomb" from trying to run Rstudio,
> as it internally uses code that fails when
>  _R_CHECK_LENGTH_1_LOGIC2_
> is activated, see the screen shot (from the very latest
> Rstudio 1.2.5019),
> at least in my case where I use a non-trival  'options(repos = ..)'
> in my startup.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Abby Spurdle
In reply to this post by Martin Maechler
> > 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'm not enthusiastic about matrices extending arrays.
If a matrix is an array, then shouldn't all vectors in R, be arrays too?

> #mockup
> class (1)
[1] "numeric" "array"

Which is a bad idea.
It contradicts the central principle that R uses "Vectors" rather than "Arrays".
And I feel that matrices are and should be, a special case of vectors.
(With their inheritance from vectors taking precedence over anything else).

If the motivation is to solve the problem of 2D arrays, automatically
being mapped to matrices:

> class (array (1, c (2, 2) ) )
[1] "matrix"

Then wouldn't it be better, to treat 2D arrays, as a special case, and
leave matrices as they are?

> #mockup
> class (array (1, c (2, 2) ) )
[1] "array2d" "matrix" "array"

Then 2D arrays would have access to both matrix and array methods...

Note, I don't want to enter into (another) discussion on the
differences between implicit class and classes defined via a class
attribute.
That's another discussion, which has little to do with my points above.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

R devel mailing list
arrays and matrices have a numeric dims attribute, vectors don't.  If
statements lead to bad code.

Bill Dunlap
TIBCO Software
wdunlap tibco.com


On Fri, Nov 15, 2019 at 1:19 PM Abby Spurdle <[hidden email]> wrote:

> > > 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'm not enthusiastic about matrices extending arrays.
> If a matrix is an array, then shouldn't all vectors in R, be arrays too?
>
> > #mockup
> > class (1)
> [1] "numeric" "array"
>
> Which is a bad idea.
> It contradicts the central principle that R uses "Vectors" rather than
> "Arrays".
> And I feel that matrices are and should be, a special case of vectors.
> (With their inheritance from vectors taking precedence over anything else).
>
> If the motivation is to solve the problem of 2D arrays, automatically
> being mapped to matrices:
>
> > class (array (1, c (2, 2) ) )
> [1] "matrix"
>
> Then wouldn't it be better, to treat 2D arrays, as a special case, and
> leave matrices as they are?
>
> > #mockup
> > class (array (1, c (2, 2) ) )
> [1] "array2d" "matrix" "array"
>
> Then 2D arrays would have access to both matrix and array methods...
>
> Note, I don't want to enter into (another) discussion on the
> differences between implicit class and classes defined via a class
> attribute.
> That's another discussion, which has little to do with my points above.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

        [[alternative HTML version deleted]]

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: class(<matrix>) |--> c("matrix", "arrary") [was "head.matrix ..."]

Dénes Tóth-2
In reply to this post by Abby Spurdle
Hi Abby,

On 11/15/19 10:19 PM, Abby Spurdle wrote:
>>> 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'm not enthusiastic about matrices extending arrays.
> If a matrix is an array, then shouldn't all vectors in R, be arrays too?

The main distinguishing feature of matrices (and arrays) vs vectors is
that they have a dimension attribute.

x <- as.list(letters[1:8]) # just to show that it generalizes not only
to atomic vectors
is.vector(x) # TRUE
inherits(x, "matrix") # FALSE

dim(x) <- c(2, 4)
is.vector(x) # FALSE
inherits(x, "matrix") # TRUE
inherits(x, "array") # FALSE, but should be TRUE for consistency

dim(x) <- c(2, 2, 2)
is.vector(x) # FALSE
inherits(x, "matrix") # FALSE
inherits(x, "array") # TRUE


A matrix should be really nothing else just an array where
length(dim(x)) == 2L.

IMHO the only special object which has dimension attribute but is not a
special case of arrays is the data.frame.


Denes



>
>> #mockup
>> class (1)
> [1] "numeric" "array"
>
> Which is a bad idea.
> It contradicts the central principle that R uses "Vectors" rather than "Arrays".
> And I feel that matrices are and should be, a special case of vectors.
> (With their inheritance from vectors taking precedence over anything else).
>
> If the motivation is to solve the problem of 2D arrays, automatically
> being mapped to matrices:
>
>> class (array (1, c (2, 2) ) )
> [1] "matrix"
>
> Then wouldn't it be better, to treat 2D arrays, as a special case, and
> leave matrices as they are?
>
>> #mockup
>> class (array (1, c (2, 2) ) )
> [1] "array2d" "matrix" "array"
>
> Then 2D arrays would have access to both matrix and array methods...
>
> Note, I don't want to enter into (another) discussion on the
> differences between implicit class and classes defined via a class
> attribute.
> That's another discussion, which has little to do with my points above.
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

class(<matrix>) |--> c("matrix", "arrary") -- and S3 dispatch

Martin Maechler
In reply to this post by Martin Maechler

TLDR: This is quite technical, still somewhat important:
     1)  R 4.0.0 will become a bit more coherent: a matrix is an array
     2)  Your package (or one you use) may be affected.


>>>>> Martin Maechler
>>>>>     on Fri, 15 Nov 2019 17:31:15 +0100 writes:

>>>>> 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 ... wrote:

    [................]
   
    >>>>> 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.

BUT it's wrong what I (and Peter and Hervé and ....) had assumed:

If I just change the class
     (as I already did a few days ago, but you must activate the change
      via environment variable, see below),

S3 dispatch does *NOT* at all pick it up:
"matrix" (and "array") are even more special here (see below),
and from Hadley's questions, in hindsight I now see that he's been aware
of that and I hereby apologize to Hadley for not having thought
and looked more, when he asked ..

Half an hour ago, I've done another source code commit (svn r77446),
to "R-devel" only, of course, and the R-devel NEWS now starts as

------------------------------------------------------------

CHANGES IN R-devel:

  USER-VISIBLE CHANGES:

    •  .... intention that the next non-patch release should be 4.0.0.

    • R now builds by default against a PCRE2 library ........
      ...................
      ...................

    • For now only active when environment variable
      _R_CLASS_MATRIX_ARRAY_ is set to non-empty, but planned to be the
      new unconditional behavior when R 4.0.0 is released:

      Newly, matrix objects also inherit from class "array", namely,
      e.g., class(diag(1)) is c("matrix", "array") which invalidates
      code (wrongly) assuming that length(class(obj)) == 1, a wrong
      assumption that is less frequently fulfilled now.  (Currently
      only after setting _R_CLASS_MATRIX_ARRAY_ to non-empty.)

      S3 methods for "array", i.e., <someFun>.array(), are now also
      dispatched for matrix objects.

------------------------------------------------------------
(where only the very last 1.5 lines paragraph is new.)

Note the following
(if you use a version of R-devel, with svn rev >= 77446; which
 you may get as a binary for Windows in about one day; everyone
 else needs to compile for the sources .. or wait a bit, maybe
 also not much longer than one day, for a docker image) :


> Sys.unsetenv("_R_CLASS_MATRIX_ARRAY_") # ==> current R behavior
> class(m <- diag(1))
[1] "matrix"
> Sys.setenv("_R_CLASS_MATRIX_ARRAY_" = "BOOH !") # ==> future R behavior
> class(m)
[1] "matrix" "array"
>
> foo <- function(x) UseMethod("foo")
> foo.array <- function(x) "made in foo.array()"
> foo(m)
[1] "made in foo.array()"
> Sys.unsetenv("_R_CLASS_MATRIX_ARRAY_")# ==> current R behavior
> foo(m)
Error in UseMethod("foo") :
  no applicable method for 'foo' applied to an object of class "c('matrix', 'double', 'numeric')"

> Sys.setenv("_R_CLASS_MATRIX_ARRAY_" = TRUE) # ==> future R behavior
> foo(m)
[1] "made in foo.array()"
> foo.A <- foo.array ; rm(foo.array)
> foo(m)
Error in UseMethod("foo") :
  no applicable method for 'foo' applied to an object of class "c('matrix', 'array', 'double', 'numeric')"
>

So, with my commit 77446, the  _R_CLASS_MATRIX_ARRAY_
environment variable also changes the

   "S3 dispatch determining class"

mentioned as 'class' in the error message (of the two cases, old
and new) above,  which in R <= 3.6.x for a numeric matrix is

    c('matrix', 'double', 'numeric')

and from R 4.0.0 on  will be

    c('matrix', 'array', 'double', 'numeric')

Note that this is *not* (in R <= 3.6.x, nor very probably in R 4.0.0)
the same as  R's  class().
Hadley calls this long class vector the  'implicit class' -- which
is a good term but somewhat conflicting with R's (i.e. R-core's)
"definition" used in the  ?class  help page (for ca. 11 years).

R's internal C code has a nice function class R_data_class2()
which computes this 'S3-dispatch-class' character (vector) for
any R object, and R_data_class2() is indeed called from (the
underlying C function of)  R's UseMethod().

Using the above fact of an error message,
I wrote a nice (quite well tested) function  my.class2()  which
returns this S3_dispatch_class() also in current versions of R:

my.class2 <- function(x) { # use a fn name not used by any sane ..
    foo.7.3.343 <- function(x) UseMethod("foo.7.3.343")
    msg <- tryCatch(foo.7.3.343(x), error=function(e) e$message)
    clm <- sub('"$', '', sub(".* of class \"", '', msg))
    if(is.language(x) || is.function(x))
        clm
    else {
        cl <- str2lang(clm)
        if(is.symbol(cl)) as.character(cl) else eval(cl)
    }
}

## str2lang() needs R >= 3.6.0:
if(getRversion() < "3.6.0") ## substitute for str2lang(), good enough here:
    str2lang <- function(s) parse(text = s, keep.source=FALSE)[[1]]

 
Now you can look at such things yourself:

## --------------------- the "interesting" cases : ---
## integer and double
my.class2( pi) # == c("double",  "numeric")
my.class2(1:2) # == c("integer", "numeric")
## matrix and array [also combined with int / double ] :
my.class2(matrix(1L, 2,3))   # == c(matrixCL, "integer", "numeric")  <<<
my.class2(matrix(pi, 2,3))   # == c(matrixCL,  "double", "numeric")  <<<
my.class2(array("A", 2:3))   # == c(matrixCL,  "character")          <<<
my.class2(array(1:24, 2:4))   # == c("array",  "integer", "numeric")
my.class2(array( pi , 2:4))   # == c("array",   "double", "numeric")
my.class2(array(TRUE, 2:4))   # == c("array", "logical")
my.class2(array(letters, 2:4)) # == c("array", "character")
my.class2(array(1:24 + 1i, 2)) # == c("array", "complex")

## other cases
my.class2(NA) # == class(NA) : "logical"
my.class2("A") # == class("B"): "character"
my.class2(as.raw(0:2)) # == "raw"
my.class2(1 + 2i) # == "complex"
my.class2(USJudgeRatings)#== "data.frame"
my.class2(class) # == "function" # also for a primitive
my.class2(globalenv()) # == "environment"
my.class2(quote(sin(x)))# == "call"
my.class2(quote(sin) )  # == "name"
my.class2(quote({})) # == class(*) == "{"
my.class2(quote((.))) # == class(*) == "("

-----------------------------------------------------

note that of course, the lines marked "<<<" above, contain
'matrixCL'  which is "matrix" in "old" (i.e. current) R,
            and is c("matrix", "array") in "new" (i.e. future) R.

Last but not least: It's quite trivial (only few words need to
be added to the sources; more to the documentation)  to add an R
function to base R which provides the same as my.class2() above,
(but much more efficiently, not via catching error messages !!),
and my current proposal for that function's name is  .class2()
{it should start with a dot ("."), as it's not for the simple
 minded average useR ... and you know how I'm happy with
 function names that do not need one single [Shift] key ...}

The current plan contains

1)  Notify CRAN package maintainers (ca 140) whose packages no
    longer pass R CMD check  when the feature is turned on
    (via setting the environment variable) in R-devel.

2a) (Some) CRAN team members set _R_CLASS_MATRIX_ARRAY_ (to non-empty),
    as part of the incoming checks, at least for all new CRAN submissions

2b) set the  _R_CLASS_MATRIX_ARRAY_ (to non-empty), as part of
    ' R CMD check --as-cran <pkg>'

3)  Before the end of 2019, change the R sources (for R-devel)
    such that it behaves as it behaves currently when the environment
    variable is set *AND* abolish this environment variable from
    the sources.  {read on to learn *why*}

Consequently (to 3), R 4.0.0 will behave as indicated, unconditionally.

Note that (as I've shown above in the first example set) this is
set up in such a manner that you can change the environment
variable during a *running* R session, and observe the effect immediately.
This however lead to some slow down of quite a bit of the R
code, because actually the environment variable has to be
checked quite often (easily dozens of times for simple R calls).

For that reason, we want to do "3)" as quickly as possible.

Please do not hesitate to ask or comment
-- here, not on Twitter, please --  noting that I'll be
basically offline for an extended weekend within 24h, now.

I hope this will eventually to lead to clean up and clarity in
R, and hence should be worth the pain of broken
back-compatibility and having to adapt your (almost always only
sub-optimally written ;-)) R code,
see also my Blog   http://bit.ly/R_blog_class_think_2x

Martin Maechler
ETH Zurich and R Core team

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
123