[Rd] dimnames incoherence?

Martin Maechler m@ech|er @end|ng |rom @t@t@m@th@ethz@ch
Wed Feb 19 21:58:51 CET 2020


>>>>> Martin Maechler 
>>>>>     on Wed, 19 Feb 2020 18:06:57 +0100 writes:

>>>>> Serguei Sokol 
>>>>>     on Wed, 19 Feb 2020 15:21:21 +0100 writes:

    >> Hi,
    >> I was bitten by a little incoherence in dimnames assignment or may be I 
    >> missed some point.
    >> Here is the case. If I assign row names via dimnames(a)[[1]], when 
    >> nrow(a)=1 then an error is thrown. But if I do the same when nrow(a) > 1 
    >> it's OK. Is one of this case works unexpectedly? Both? Neither?

    >> a=as.matrix(1)
    >> dimnames(a)[[1]]="a" # error: 'dimnames' must be a list

    >> aa=as.matrix(1:2)
    >> dimnames(aa)[[1]]=c("a", "b") # OK

    >> In the second case, dimnames(aa) is not a list (like in the first case) 
    >> but it works.
    >> I would expect that the both work or neither.

    > I agree (even though I'm strongly advising people to use '<-'
    > instead of '=');
    > which in this case helps you get the name of the function really
    > involved:  It is  `dimnames<-`  (which is implemented in C
    > entirely, for matrices and other arrays).

As a matter of fact, I wrote too quickly, the culprit here is
the  `[[<-`  function (rather than `dimnames<-`),
which has a special "inconsistency" feature when used to "add to NULL";
almost surely inherited from S,  but I now think we should
consider dropping on the occasion of aiming for  R 4.0.0 :

It's documented in ?Extract  that  length 1  `[[.]]`-assignment works
specially for NULL (and dimnames(.) are NULL here).

Note you need to read and understand one of the tougher sections
in the official  'R Language Definition'  Manual,
section -- 3.4.4 Subset assignment ---
i.e.,
https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Subset-assignment

notably this part: 

Nesting of complex assignments is evaluated recursively 

     names(x)[3] <- "Three"

is equivalent to

     `*tmp*` <- x
     x <- "names<-"(`*tmp*`, value="[<-"(names(`*tmp*`), 3, value="Three"))
     rm(`*tmp*`)

and then, apply this to our    dimnames(a)[[1]] <- "a"
and so  replace

 -  'names<-' by 'dimnames<-'
 -  '[<-'     by '[[<-'

----------

Here is the rest of my analysis as valid R code
{this is not new, Peter Dalgaard had explained this 10 or 20
 years ago to a mailing list audience IIRC} : 

## MM: The problematic behavior (bug ?) is in `[[<-`, not in `dimnames<-` :

`[[<-`(NULL, 1,   "a"     ) # gives  "a"  (*not* a list)
`[[<-`(NULL, 1, c("a","b")) # gives list(c("a","b"))  !!

##==> in C code: in  subassign.c  [ ~/R/D/r-devel/R/src/main/subassign.c ]
##==> function (~ 340 lines)
##            do_subassign2_dflt(SEXP call, SEXP op, SEXP args, SEXP rho)
## has
"
line svn r.  svn auth. c.o.d.e...
---- ------  --------- ----------------------------------------------
1741   4166      ihaka     if (isNull(x)) {
1742  45446     ripley         if (isNull(y)) {
1743  76166       luke             UNPROTECT(2); /* args, y */
1744   4166      ihaka             return x;
1745  45446     ripley         }
1746  35680    murdoch         if (length(y) == 1)
1747  68094       luke             x = allocVector(TYPEOF(y), 0);
1748  24954     ripley         else
1749  68094       luke             x = allocVector(VECSXP, 0);
1750   1820      ihaka     }
---- ------  --------- ----------------------------------------------
"
## so clearly, in case the value is of length 1, no list is created .

## For dimnames<-  Replacing NULL by list()  should be done in both cases , and then things work :
`[[<-`(list(), 1,   "a"     ) # gives list( "a" )
`[[<-`(list(), 1, c("a","b")) # gives list(c("a","b"))  !!

## but the problem here is that  `[[<-` at this time in the game
## does *not* know that it comes from dimnames<- ....

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

If we change the behavior  NULL--[[--assignment from

 `[[<-`(NULL, 1, "a" ) # gives  "a"  (*not* a list)

to

 `[[<-`(NULL, 1, "a" ) # gives  list("a")


then we have more consistency there *and* your bug is fixed too.
Of course, in other situations back-compatibility would be
broken as well.

At the moment, I think we (R Core Team) should consider doing
that here.

Martin



    >> Your thoughts are welcome.

    > I think we'd be happy if you report this formally on R's
    > bugzilla - https://bugs.r-project.org/ - as a bug.

    --> https://www.r-project.org/bugs.html

    >> From reading bugs.html you note that you should ask for
    >> an account there;
    > as I'm one of the people who get such request by e-mail,
    > in this case, I can do it directly (if you confirm you'd
    > want in a private e-mail).

    >> Best, Serguei.

    >> PS the same apply for dimnames(a)[[2]]<-.

    > (of course)

    > NB *and* importantly, the buglet is still in current
    > versions of R

    > Best, Martin

    >>> sessionInfo()
    >> R version 3.6.1 (2019-07-05) Platform:
    >> x86_64-pc-linux-gnu (64-bit) Running under: Mageia 7

    >> Matrix products: default BLAS/LAPACK:
    >> /home/opt/OpenBLAS/lib/libopenblas_sandybridge-r0.3.6.so

    >> locale:  [1] LC_CTYPE=fr_FR.UTF-8       LC_NUMERIC=C  [3]
    >> LC_TIME=fr_FR.UTF-8        LC_COLLATE=fr_FR.UTF-8  [5]
    >> LC_MONETARY=fr_FR.UTF-8    LC_MESSAGES=fr_FR.UTF-8  [7]
    >> LC_PAPER=fr_FR.UTF-8       LC_NAME=C  [9]
    >> LC_ADDRESS=C               LC_TELEPHONE=C [11]
    >> LC_MEASUREMENT=fr_FR.UTF-8 LC_IDENTIFICATION=C

    >> attached base packages: [1] parallel  stats     graphics 
    >> grDevices utils     datasets methods [8] base

    >> other attached packages: [1] multbxxc_1.0.1           
    >> rmumps_5.2.1-11 [3] arrApply_2.1             
    >> RcppArmadillo_0.9.800.4.0 [5] Rcpp_1.0.3               
    >> slam_0.1-47 [7] nnls_1.4

    >> loaded via a namespace (and not attached): [1]
    >> compiler_3.6.1   tools_3.6.1      codetools_0.2-16

    >> ______________________________________________
    >> R-devel using r-project.org mailing list
    >> https://stat.ethz.ch/mailman/listinfo/r-devel

    > ______________________________________________
    > R-devel using r-project.org mailing list
    > https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list