From g@bembecker @end|ng |rom gm@||@com  Sat Nov  2 20:40:16 2019
From: g@bembecker @end|ng |rom gm@||@com (Gabriel Becker)
Date: Sat, 2 Nov 2019 12:40:16 -0700
Subject: [Rd] 
 head.matrix can return 1000s of columns -- limit to n or add
 new argument?
In-Reply-To: <CAD4oTHF1+PdJX-Qq=JZwafhGNatDu9AZVD0prCAvyJFL9bLzVg@mail.gmail.com>
References: <CAPRVBcxsAkcgr3mDc4skTe8DTxJaYe2xyhk3QMk3odW1MGcyNA@mail.gmail.com>
 <CAB8pepxS2mRtd+522OwjixnM6ZjYxb+X0dc4vMGn6QxdFYBmVQ@mail.gmail.com>
 <CAD4oTHH=LpeEj6h6xYdOGsreS-GDCGdgJV5wpaUR3Pjuh5_M1w@mail.gmail.com>
 <CAPRVBczYZHO3JaFVfNeNNV0-YMRvX3CUYhUvLCjophDEoP+XgQ@mail.gmail.com>
 <23935.14449.965488.684663@stat.math.ethz.ch>
 <CAPRVBcwMY=GAVfFeCwowQsxP31Y=_B2ducosThN+8V91WESB8Q@mail.gmail.com>
 <20449_1568703158_x8H6qIDG009669_f8285123-371f-5d4b-1281-6cc085dba122@fredhutch.org>
 <22204_1568723392_x8HCSG3F015456_674779E0-B1F6-4DC2-9F1C-D5D48B044B66@mcmaster.ca>
 <AD725242-0FB7-4004-9F16-304E345A363A@mcmaster.ca>
 <23937.1791.389379.103733@stat.math.ethz.ch>
 <CAD4oTHF_e4rtHu0S5bUu38+kQSEHXwun3Sv9-CbK+xN9tSc2hA@mail.gmail.com>
 <CAD4oTHFf7Zp+Xe3jvv7oirLWgZm7ZiSNWZvbrEsqJGfrL6Q2wQ@mail.gmail.com>
 <23993.29737.690600.313456@stat.math.ethz.ch>
 <38105A28-07AE-48F6-A4A4-0C1FCCCBFBDC@gmail.com>
 <23995.62027.969336.196344@stat.math.ethz.ch>
 <CAD4oTHF1+PdJX-Qq=JZwafhGNatDu9AZVD0prCAvyJFL9bLzVg@mail.gmail.com>
Message-ID: <CAD4oTHHxHmK6jmBSGrBsyZnCnxtLTrSyGyL726VHJd=rsGri8Q@mail.gmail.com>

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 <gabembecker at gmail.com>
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 <maechler at stat.math.ethz.ch>
> 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 <
>> maechler at stat.math.ethz.ch> 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: pd.mes at cbs.dk  Priv: PDalgd at gmail.com
>>
>>
>>
>>
>>
>>
>>
>>
>>

	[[alternative HTML version deleted]]



[Rd] head.matrix can return 1000s of columns -- limit to n or add new argument?
Gabriel Becker