From m@ech|er @end|ng |rom @t@t@m@th@ethz@ch  Wed Sep 25 09:15:54 2019
From: m@ech|er @end|ng |rom @t@t@m@th@ethz@ch (Martin Maechler)
Date: Wed, 25 Sep 2019 09:15:54 +0200
Subject: [Rd] '==' operator: inconsistency in data.frame(...) == NULL
In-Reply-To: <2077d941-9a2e-8acc-3125-cf10a7fe8deb@mpiib-berlin.mpg.de>
References: <9075d086-7945-b759-f311-765d626b7a61@mpiib-berlin.mpg.de>
 <23928.43189.410927.15494@stat.math.ethz.ch>
 <c21fa68d-00da-dcc1-6390-dce52c889748@mpiib-berlin.mpg.de>
 <f144303d-0fa6-7827-bca3-2587a43c3484@mpiib-berlin.mpg.de>
 <1bbabc36-43c8-aad6-4a08-b310d13c8938@mpiib-berlin.mpg.de>
 <94e5fbbe-6f03-9b69-8abf-ebeced33a016@mpiib-berlin.mpg.de>
 <23937.60510.182530.176708@stat.math.ethz.ch>
 <23937.63728.859845.525356@stat.math.ethz.ch>
 <2077d941-9a2e-8acc-3125-cf10a7fe8deb@mpiib-berlin.mpg.de>
Message-ID: <23947.5162.267570.590918@stat.math.ethz.ch>

>>>>> Hilmar Berger 
>>>>>     on Tue, 24 Sep 2019 19:31:51 +0200 writes:

    > Dear Martin,
    > thanks a lot for looking into this. Of course you were right that the 
    > fix was not complete - I apologize for not having tested what I believed 
    > to be the solution.

    > My comments on the S4 classes seemed to stem from a misunderstanding on 
    > my side. I now believe to understand that S4 classes that inherit from R 
    > base object types might dispatch Ops for the same object types.

    > If the base object value of such S4 classes is unset and therefore 
    > empty, this empty value will be passed on to e.g. Ops.data.frame where 
    > it would trigger the same issue as e.g. logical(0).

    > setClass("MyClass", slots = list(x="numeric", label="character"), 
    > contains = "numeric")
    > a = new("MyClass", x=3, label="FOO")
    > a at .Data

    >> logical(0)

    > a == data.frame(a=1:3)
    > # error

    > I understand that this is all as expected and the error should most 
    > likely disappear with the fix you submitted for other 0-extent cases.


    > Thanks again and best regards,
    > Hilmar

You are welcome!
Indeed, I had modified code in R-devel that makes these Ops work with many
0-extent data frames (compatibly with corresponding 0-extent
matrices).
Thank you, Hilmar!

In addition I confirm that indeed comparison with S4 objects as
above now works too :


R Under development (unstable) (2019-09-23 r77210) -- "Unsuffered Consequences"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

  ## {learn: you can use the return value of setClass() !}

  MY  <- setClass("MyClass", slots = list(x="numeric",label="character"), 
                             contains = "numeric")
  a <- MY(x=pi, label="FOO")
  D3 <- data.frame(a=1:3)

> identical(D3 == a, D3 == logical())
[1] TRUE
> 

Best,
Martin

    > Am 18/09/2019 um 11:29 schrieb Martin Maechler:
    >>>>>>> Martin Maechler
    >>>>>>> on Wed, 18 Sep 2019 10:35:42 +0200 writes:
    >> >>>>> Hilmar Berger
    >> >>>>>     on Sat, 14 Sep 2019 13:31:27 +0200 writes:
    >> 
    >> >> Dear all,
    >> >> I did some more tests regarding the == operator in Ops.data.frame (see
    >> >> below).? All tests done in R 3.6.1 (x86_64-w64-mingw32).
    >> 
    >> >> I find that errors are thrown also when comparing a zero length
    >> >> data.frame to atomic objects with length>0 which should be a valid case
    >> >> according to the documentation. This can be traced to a check in the
    >> >> last line of Ops.data.frame which tests for the presence of an empty
    >> >> result value (i.e. list() ) but does not handle a list of empty values
    >> >> (i.e. list(logical(0))) which in fact is generated in those cases.
    >> 
    >> >> There  is a simple fix (see also below).
    >> 
    >> > I'm pretty sure what you write above is wrong:  For some reason
    >> > you must have changed more in your own version of Ops.data.frame :
    >> 
    >> > Because there's a line
    >> 
    >> > value <- unlist(value, ...)
    >> 
    >> > there, value is *not*  list(logical(0)) there, but rather  logical(0)
    >> > and then indeed, your proposed line change (at the end of Ops.data.frame)
    >> > has no effect for the examples you give.
    >> 
    >> On the other hand, there *is* a simple "fix" at the end of
    >> Ops.data.frame()  which makes all your examples "work" (i.e. not
    >> give an error), namely
    >> 
    >> ----------------------------------------------------------------------
    >> 
    >> @@ -1685,7 +1684,7 @@
    >> else { ## 'Logic' ("&","|")  and  'Compare' ("==",">","<","!=","<=",">=") :
    >> value <- unlist(value, recursive = FALSE, use.names = FALSE)
    >> matrix(if(is.null(value)) logical() else value,
    >> -	       nrow = nr, dimnames = list(rn,cn))
    >> +	       nrow = nr, ncol = length(cn), dimnames = list(rn,cn))
    >> }
    >> 
    >> ----------------------------------------------------------------------
    >> 
    >> i.e., explicitly specifying 'ncol' compatibly with the column names.
    >> However, I guess that this change would *not* signal errors
    >> where it *should* and so am *not* (yet?) proposing to "do" it.
    >> 
    >> Another remark, on  S4  which you've raised several times:
    >> As you may know that the 'Matrix' package (part of every
    >> "regular" R installation) uses S4 "everywhere" and it does
    >> define many methods for its Matrix classes, all in source file  Matrix/R/Ops.R
    >> the development version (in svn / subversion) being online on R-forge here:
    >> 
    >> https://r-forge.r-project.org/scm/viewvc.php/pkg/Matrix/R/Ops.R?view=markup&root=matrix
    >> 
    >> and "of course", there we define S4 group methods for Ops all
    >> the time, and (almost) never S3 ones...
    >> [[but I hope you don't want to start combining data frames
    >> with Matrix package matrices, now !]]
    >> 
    >> Martin Maechler
    >> ETH Zurich  and  R Core Team



[Rd] '==' operator: inconsistency in data.frame(...) == NULL
Martin Maechler