[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