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

Martin Maechler m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Fri Nov 1 09:52:27 CET 2019


>>>>> 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 using 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 using cbs.dk  Priv: PDalgd using gmail.com



More information about the R-devel mailing list