

Dear all,
I just stumbled upon some behavior of the == operator which is at least
somewhat inconsistent.
R version 3.6.1 (20190705)  "Action of the Toes"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64w64mingw32/x64 (64bit)
> list(a=1:3, b=LETTERS[1:3]) == NULL
logical(0)
> matrix(1:6, 2,3) == NULL
logical(0)
> data.frame(a=1:3, b=LETTERS[1:3]) == NULL # same for == logical(0)
Error in matrix(if (is.null(value)) logical() else value, nrow = nr,
dimnames = list(rn, :
length of 'dimnames' [2] not equal to array extent
> data.frame(NULL) == 1
<0 x 0 matrix>
> data.frame(NULL) == NULL
<0 x 0 matrix>
> data.frame(NULL) == logical(0)
<0 x 0 matrix>
I wonder if data.frame(<some nonempty data>) == NULL should also return
a value instead of an error. R help reads:
"At least one of x and y must be an atomic vector, but if the other
is a list *R* attempts to coerce it to the type of the atomic vector:
this will succeed if the list is made up of elements of length one that
can be coerced to the correct type.
If the two arguments are atomic vectors of different types, one is
coerced to the type of the other, the (decreasing) order of precedence
being character, complex, numeric, integer, logical and raw."
It is not clear from the help what to expect for NULL or empty atomic
vectors. It is also strange that for list() there is no error but for
data.frame() with the same data an error is thrown. I can see that there
might be reasons to return logical(0) instead of FALSE, but I do not
fully understand why there should be differences between e.g. matrix()
and data.frame().
Also, It is at least somewhat strange that data.frame(NULL) == NULL and
similar expressions return an empty matrix, while comparing a normal
filled matrix to NULL returns logical(0).
Even if this behavior is expected, the error message shown by
data.frame(...) == NULL is not very informative.
Thanks and best regards,
Hilmar
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Hilmar Berger
>>>>> on Wed, 4 Sep 2019 15:25:46 +0200 writes:
> Dear all,
> I just stumbled upon some behavior of the == operator which is at least
> somewhat inconsistent.
> R version 3.6.1 (20190705)  "Action of the Toes"
> Copyright (C) 2019 The R Foundation for Statistical Computing
> Platform: x86_64w64mingw32/x64 (64bit)
>> list(a=1:3, b=LETTERS[1:3]) == NULL
> logical(0)
>> matrix(1:6, 2,3) == NULL
> logical(0)
>> data.frame(a=1:3, b=LETTERS[1:3]) == NULL # same for == logical(0)
> Error in matrix(if (is.null(value)) logical() else value, nrow = nr,
> dimnames = list(rn, :
> length of 'dimnames' [2] not equal to array extent
>> data.frame(NULL) == 1
> <0 x 0 matrix>
>> data.frame(NULL) == NULL
> <0 x 0 matrix>
>> data.frame(NULL) == logical(0)
> <0 x 0 matrix>
> I wonder if data.frame(<some nonempty data>) == NULL should also return
> a value instead of an error. R help reads:
> "At least one of x and y must be an atomic vector, but
> if the other is a list R attempts to coerce it to the
> type of the atomic vector: this will succeed if the list
> is made up of elements of length one that can be coerced
> to the correct type.
> If the two arguments are atomic vectors of different
> types, one is coerced to the type of the other, the
> (decreasing) order of precedence being character, complex,
> numeric, integer, logical and raw."
> It is not clear from the help what to expect for NULL or
> empty atomic vectors.
Well, strictly speaking an error would be expected for NULL,
as it is *not* an atomic vector, and your main issue
" data.frame(..) == NULL "
would already be settled by the first half sentence from the
doc, and strictly speaking, even data.frame(NULL) == NULL
"should" return an error ((Note: I'm not saying it really
should, but at least the reference does not say it should work at all))
Now, logical(0) on the other hand *is* an atomic vector ...
> It is also strange that for list()
> there is no error but for data.frame() with the same data
> an error is thrown. I can see that there might be reasons
> to return logical(0) instead of FALSE, but I do not fully
> understand why there should be differences between
> e.g. matrix() and data.frame().
Well, a [regular base R] matrix() is atomic and a data frame is not.
> Also, It is at least somewhat strange that
> data.frame(NULL) == NULL and similar expressions return an
> empty matrix, while comparing a normal filled matrix to
> NULL returns logical(0).
> Even if this behavior is expected, the error message shown
> by data.frame(...) == NULL is not very informative.
I'm not at all sure there's any need for a change here.
I would say the following general thinking should be applied
1. The general rule that '==' should be used only for comparing
atomic objects (as it returns an atomic object, a 'logical' with
corresponding attributes), is really principal
and using '==' for anything else has never been "the idea".
2. There are (two) "semiexceptions" to the above:
2a) Sometimes it has been convenient to treat NULL as if it was
a zerolength atomic object (of "arbitrary" type/mode).
2b) data.frame()s "should typically" behave like matrices in
many situations, notably when indexed {and that rule is
violated (on purpose) by tibbles .. ("drop=FALSE" etc, but
that's another story)}
So because of these exceptions, you and possibly others may
think '==' should "work" with data.frame()s and/or NULL, but
I would not tend to agree.
> Thanks and best regards,
> Hilmar
You are welcome!
Martin
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Dear Martin,
On 11/09/2019 09:56, Martin Maechler wrote:
>
> > I wonder if data.frame(<some nonempty data>) == NULL should also return
> > a value instead of an error. R help reads:
>
> > "At least one of x and y must be an atomic vector, but
> > if the other is a list R attempts to coerce it to the
> > type of the atomic vector: this will succeed if the list
> > is made up of elements of length one that can be coerced
> > to the correct type.
>
> > If the two arguments are atomic vectors of different
> > types, one is coerced to the type of the other, the
> > (decreasing) order of precedence being character, complex,
> > numeric, integer, logical and raw."
>
> > It is not clear from the help what to expect for NULL or
> > empty atomic vectors.
>
> Well, strictly speaking an error would be expected for NULL,
> as it is *not* an atomic vector, and your main issue
>
> " data.frame(..) == NULL "
>
> would already be settled by the first half sentence from the
> doc, and strictly speaking, even data.frame(NULL) == NULL
> "should" return an error ((Note: I'm not saying it really
> should, but at least the reference does not say it should work at all))
Thanks, this explanation makes total sense to me. I did not consider
that NULL might be nonatomic. Strangely, is.atomic(NULL) returns TRUE.
On the other hand, I understand that one would not like to treat it like
atomic in ==.
However, in this case one might expect that the error message would be
more like that for S4 objects (which always seem to report an
informative error message for ==):
> Pos < setClass("Pos", slots = c(latitude = "numeric", longitude =
"numeric", altitude = "numeric"))
> p = Pos()
> p == NULL
Error in p == NULL :
comparison (1) is possible only for atomic and list types
> p == "FOO"
Error in p == "FOO" :
comparison (1) is possible only for atomic and list types
In the data.frame()==NULL cases I have the impression that the fact that
both sides are nonatomic is not properly detected and therefore R tries
to go on with the == method for data.frames.
From a cursory check in Ops.data.frame() and some debugging I have the
impression that the case of the second argument being nonatomic or
empty is not handled at all and the function progresses until the end,
where it fails in the last step on an empty value:
matrix(unlist(value, recursive = FALSE, use.names = FALSE),
nrow = nr, dimnames = list(rn, cn))
Best regards,
Hilmar

Dr. Hilmar Berger, MD
Max Planck Institute for Infection Biology
Charitéplatz 1
D10117 Berlin
GERMANY
Phone: + 49 30 28460 430
Fax: + 49 30 28460 401
EMail: [hidden email]
Web : www.mpiibberlin.mpg.de
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Another example where a data.frame is compared to (here nonnull,
nonempty) nonatomic values in Ops.data.frame, resulting in an error
message:
setClass("FOOCLASS2",
slots = c(M="matrix")
)
ma = new("FOOCLASS2", M=matrix(rnorm(300), 30,10))
> isS4(ma)
[1] TRUE
> ma == data.frame(a=1:3)
Error in eval(f) : dims [product 1] do not match the length of object [3]
As for the NULL/logical(0) cases I would suggest to explicitly test for
invalid conditions in Ops.data.frame and generate a comprehensible
message (e.g. "comparison is possible only for atomic and list types")
if appropriate.
Best regards,
Hilmar
On 11/09/2019 11:55, Hilmar Berger wrote:
>
> In the data.frame()==NULL cases I have the impression that the fact
> that both sides are nonatomic is not properly detected and therefore
> R tries to go on with the == method for data.frames.
>
> From a cursory check in Ops.data.frame() and some debugging I have the
> impression that the case of the second argument being nonatomic or
> empty is not handled at all and the function progresses until the end,
> where it fails in the last step on an empty value:
>
> matrix(unlist(value, recursive = FALSE, use.names = FALSE),
> nrow = nr, dimnames = list(rn, cn))

Dr. Hilmar Berger, MD
Max Planck Institute for Infection Biology
Charitéplatz 1
D10117 Berlin
GERMANY
Phone: + 49 30 28460 430
Fax: + 49 30 28460 401
EMail: [hidden email]
Web : www.mpiibberlin.mpg.de
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Sorry, I can't reproduce the example below even on the same machine.
However, the following example produces the same error as NULL values in
prior examples:
> setClass("FOOCLASS",
+ representation("list")
+ )
> ma = new("FOOCLASS", list(M=matrix(rnorm(300), 30,10)))
> isS4(ma)
[1] TRUE
> data.frame(a=1:3) == ma
Error in matrix(unlist(value, recursive = FALSE, use.names = FALSE),
nrow = nr, :
length of 'dimnames' [2] not equal to array extent
Best,
Hilmar
On 11/09/2019 12:24, Hilmar Berger wrote:
> Another example where a data.frame is compared to (here nonnull,
> nonempty) nonatomic values in Ops.data.frame, resulting in an error
> message:
>
> setClass("FOOCLASS2",
> slots = c(M="matrix")
> )
> ma = new("FOOCLASS2", M=matrix(rnorm(300), 30,10))
>
> > isS4(ma)
> [1] TRUE
> > ma == data.frame(a=1:3)
> Error in eval(f) : dims [product 1] do not match the length of object [3]
>
> As for the NULL/logical(0) cases I would suggest to explicitly test
> for invalid conditions in Ops.data.frame and generate a comprehensible
> message (e.g. "comparison is possible only for atomic and list types")
> if appropriate.
>
> Best regards,
> Hilmar
>
>
> On 11/09/2019 11:55, Hilmar Berger wrote:
>>
>> In the data.frame()==NULL cases I have the impression that the fact
>> that both sides are nonatomic is not properly detected and therefore
>> R tries to go on with the == method for data.frames.
>>
>> From a cursory check in Ops.data.frame() and some debugging I have
>> the impression that the case of the second argument being nonatomic
>> or empty is not handled at all and the function progresses until the
>> end, where it fails in the last step on an empty value:
>>
>> matrix(unlist(value, recursive = FALSE, use.names = FALSE),
>> nrow = nr, dimnames = list(rn, cn))
>

Dr. Hilmar Berger, MD
Max Planck Institute for Infection Biology
Charitéplatz 1
D10117 Berlin
GERMANY
Phone: + 49 30 28460 430
Fax: + 49 30 28460 401
EMail: [hidden email]
Web : www.mpiibberlin.mpg.de
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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_64w64mingw32).
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).
There are other issues with the S4 class example (i.e. data.frame() ==
<s4_object with representation as list>) which fails for different reasons.
##############################################################################
d_0 = data.frame(a = numeric(0)) # zero length data.frame
d_00 = data.frame(numeric(0)) # zero length data.frame without names
names(d_00) < NULL # remove names to obtain value being an empty list()
at the end of Ops.data.frame
d_3 = data.frame(a=1:3) # nonempty data.frame
m_0 = matrix(logical(0)) # zero length matrix
#
# error A:
# Error in matrix(if (is.null(value)) logical() else value, nrow = nr,
dimnames = list(rn, :
# length of 'dimnames' [2] not equal to array extent
d_0 == 1 # error A
d_00 == 1 # <0 x 0 matrix>
d_3 == 1 # <3 x 1 matrix>
d_0 == logical(0) # error A
d_00 == logical(0) # <0 x 0 matrix>
d_3 == logical(0) # error A
d_0 == NULL # error A
d_00 == NULL # <0 x 0 matrix>
d_3 == NULL # error A
m_0 == d_0 # error A
m_0 == d_00 # <0 x 0 matrix>
m_0 == d3 # error A
# empty matrix for comparison
m_0 == 1 # < 0 x 1 matrix>
m_0 == logical(0) # < 0 x 1 matrix>
m_0 == NULL # < 0 x 1 matrix>
# All errors above could be solved by changing the last line in
Ops.data.frame from
# matrix(if (is.null(value)) logical() else value, nrow = nr, dimnames =
list(rn, cn))
# to
# matrix(if (length(value)==0) logical() else value, nrow = nr, dimnames
= list(rn, cn))
# Alternatively or in addition one could add an explicit test for
data.frame() == NULL if desired and raise an error
#########################################################################################
# nonempty return value but failing in the same code line due to
incompatible dimensions.
# should Ops.data.frame at all be dispatched for <data.frame> == <S4
object> ?
setClass("FOOCLASS",
representation("list")
)
ma = new("FOOCLASS", list(M=matrix(rnorm(300), 30,10)))
isS4(ma)
d_3 == ma # error A
##########################################################################################
Best regards,
Hilmar
Am 11/09/2019 um 13:26 schrieb Hilmar Berger:
> Sorry, I can't reproduce the example below even on the same machine.
> However, the following example produces the same error as NULL values
> in prior examples:
>
> > setClass("FOOCLASS",
> + representation("list")
> + )
> > ma = new("FOOCLASS", list(M=matrix(rnorm(300), 30,10)))
> > isS4(ma)
> [1] TRUE
> > data.frame(a=1:3) == ma
> Error in matrix(unlist(value, recursive = FALSE, use.names = FALSE),
> nrow = nr, :
> length of 'dimnames' [2] not equal to array extent
>
> Best,
> Hilmar
>
>
> On 11/09/2019 12:24, Hilmar Berger wrote:
>> Another example where a data.frame is compared to (here nonnull,
>> nonempty) nonatomic values in Ops.data.frame, resulting in an error
>> message:
>>
>> setClass("FOOCLASS2",
>> slots = c(M="matrix")
>> )
>> ma = new("FOOCLASS2", M=matrix(rnorm(300), 30,10))
>>
>> > isS4(ma)
>> [1] TRUE
>> > ma == data.frame(a=1:3)
>> Error in eval(f) : dims [product 1] do not match the length of object
>> [3]
>>
>> As for the NULL/logical(0) cases I would suggest to explicitly test
>> for invalid conditions in Ops.data.frame and generate a
>> comprehensible message (e.g. "comparison is possible only for atomic
>> and list types") if appropriate.
>>
>> Best regards,
>> Hilmar
>>
>>
>> On 11/09/2019 11:55, Hilmar Berger wrote:
>>>
>>> In the data.frame()==NULL cases I have the impression that the fact
>>> that both sides are nonatomic is not properly detected and
>>> therefore R tries to go on with the == method for data.frames.
>>>
>>> From a cursory check in Ops.data.frame() and some debugging I have
>>> the impression that the case of the second argument being nonatomic
>>> or empty is not handled at all and the function progresses until the
>>> end, where it fails in the last step on an empty value:
>>>
>>> matrix(unlist(value, recursive = FALSE, use.names = FALSE),
>>> nrow = nr, dimnames = list(rn, cn))
>>
>
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> 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_64w64mingw32).
> 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.
Note also that your analysis  treating all 0extent data
frames or matrices the same  is very incomplete.
A 0 x 0 matrix is not the same as a 0 x 1 matrix etc, and
similar for data frames.
Here's an extended "testing" script which takes into account
some of the above :
##
d0 < data.frame(a = numeric(0)) # zero length data.frame
d00 < unname(d0) # zero length data.frame __without names__
d3 < data.frame(a=1:3) # nonempty data.frame
d30. < d3[,FALSE] # 3 x 0  take into account, too !
d30 < unname(d30.)
m01. < matrix(,0,1, dimnames=list(NULL,"a")) # 0 x 1 matrix with dimnames
m01 < unname(m01.)
m00. < matrix(,0,0, dimnames=list(NULL,NULL)) # 0 x 0 matrix with dimnames
m00 < unname(m00.)
m3 < data.matrix(d3)
##
## error A:
## Error in matrix(if (is.null(value)) logical() else value, nrow = nr, dimnames = list(rn, :
## length of 'dimnames' [2] not equal to array extent
d0 == 1 # error A
d00 == 1 # <0 x 0 matrix>
d30. == 1 # <3 x 0 matrix>
d30 == 1 # <3 x 0 matrix>
d3 == 1 # <3 x 1 matrix>
d0 == logical(0) # error A
d00 == logical(0) # <0 x 0 matrix>
d30. == logical() # <3 x 0 matrix>
d30 == logical() # <3 x 0 matrix>
d3 == logical(0) # error A
d0 == NULL # error A
d00 == NULL # <0 x 0 matrix>
d30. == NULL # <3 x 0 matrix>
d30 == NULL # <3 x 0 matrix>
d3 == NULL # error A
m00 == d0 # error A
m00 == d00 # <0 x 0 matrix>
m00 == d3 # error A
# 0length matrix for comparison :
identical(m00., m00. == 1) ## 0 x 0 matrix *with* "invisible" dimnames [ NULL, NULL ]
identical(m00., m00. == logical(0))
identical(m00., m00. == NULL)
identical(m00, m00 == 1) ## 0 x 0 matrix w/o dimnames
identical(m00, m00 == logical(0))
identical(m00, m00 == NULL)
## 0 x 1 
identical(m01., m01. == 1) # < 0 x 1 matrix> *with* dimnames
identical(m01., m01. == logical(0)) # " " "
identical(m01., m01. == NULL) # " " "
identical(m01, m01 == 1) # < 0 x 1 matrix> w/o dimnames
identical(m01, m01 == logical(0)) # < 0 x 1 matrix>
identical(m01, m01 == NULL) # < 0 x 1 matrix>
##
Best regards,
Martin
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> 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_64w64mingw32).
>> 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 Rforge here:
https://rforge.rproject.org/scm/viewvc.php/pkg/Matrix/R/Ops.R?view=markup&root=matrixand "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
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


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@.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 0extent cases.
Thanks again and best regards,
Hilmar
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_64w64mingw32).
>
> >> 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 Rforge here:
>
> https://rforge.rproject.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
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> 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@.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 0extent cases.
> Thanks again and best regards,
> Hilmar
You are welcome!
Indeed, I had modified code in Rdevel that makes these Ops work with many
0extent data frames (compatibly with corresponding 0extent
matrices).
Thank you, Hilmar!
In addition I confirm that indeed comparison with S4 objects as
above now works too :
R Under development (unstable) (20190923 r77210)  "Unsuffered Consequences"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64pclinuxgnu (64bit)
## {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_64w64mingw32).
>>
>> >> 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 Rforge here:
>>
>> https://rforge.rproject.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
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel

