On Sat, Dec 12, 2015 at 3:54 AM, Martin Maechler <maechler at stat.math.ethz.ch> wrote:>>>>>> Henrik Bengtsson <henrik.bengtsson at gmail.com> >>>>>> on Fri, 11 Dec 2015 08:20:55 -0800 writes: > > > On Fri, Dec 11, 2015 at 8:10 AM, David Winsemius <dwinsemius at comcast.net> wrote: > >> > >>> On Dec 11, 2015, at 5:38 AM, Dario Beraldi <dario.beraldi at gmail.com> wrote: > >>> > >>> Hi All, > >>> > >>> I'd like to understand the reason why stopifnot(logical(0) == x) doesn't > >>> (never?) throw an exception, at least in these cases: > >> > >> The usual way to test for a length-0 logical object is to use length(): > >> > >> x <- logical(0) > >> > >> stopifnot( !length(x) & mode(x)=="logical" ) > > > I found > > > stopifnot(!length(x), mode(x) == "logical") > > > more helpful when troubleshooting, because it will tell you whether > > it's !length(x) or mode(x) == "logical" that is FALSE. It's as if you > > wrote: > > > stopifnot(!length(x)) > > stopifnot(mode(x) == "logical") > > > /Henrik > > Yes, indeed, thank you Henrik --- and Jeff Newmiller who's nice > humorous reply added other relevant points. > > As author stopifnot(), I do agree with Dario's "gut feeling" > that stopifnot() "somehow ought to do the right thing" > in cases such as > > stopifnot(dim(x) == c(3,4)) > > which is really subtle version of his cases > {But the gut feeling is wrong, as I argue from now on}.Personally, I think the problem there is that people forget that == is vectorised, and for a non-vectorised equality check you really should use identical: stopifnot(identical(dim(x), c(3,4))) Hadley -- http://had.co.nz/
On 12/12/2015 9:08 AM, Hadley Wickham wrote:> On Sat, Dec 12, 2015 at 3:54 AM, Martin Maechler > <maechler at stat.math.ethz.ch> wrote: >>>>>>> Henrik Bengtsson <henrik.bengtsson at gmail.com> >>>>>>> on Fri, 11 Dec 2015 08:20:55 -0800 writes: >> >> > On Fri, Dec 11, 2015 at 8:10 AM, David Winsemius <dwinsemius at comcast.net> wrote: >> >> >> >>> On Dec 11, 2015, at 5:38 AM, Dario Beraldi <dario.beraldi at gmail.com> wrote: >> >>> >> >>> Hi All, >> >>> >> >>> I'd like to understand the reason why stopifnot(logical(0) == x) doesn't >> >>> (never?) throw an exception, at least in these cases: >> >> >> >> The usual way to test for a length-0 logical object is to use length(): >> >> >> >> x <- logical(0) >> >> >> >> stopifnot( !length(x) & mode(x)=="logical" ) >> >> > I found >> >> > stopifnot(!length(x), mode(x) == "logical") >> >> > more helpful when troubleshooting, because it will tell you whether >> > it's !length(x) or mode(x) == "logical" that is FALSE. It's as if you >> > wrote: >> >> > stopifnot(!length(x)) >> > stopifnot(mode(x) == "logical") >> >> > /Henrik >> >> Yes, indeed, thank you Henrik --- and Jeff Newmiller who's nice >> humorous reply added other relevant points. >> >> As author stopifnot(), I do agree with Dario's "gut feeling" >> that stopifnot() "somehow ought to do the right thing" >> in cases such as >> >> stopifnot(dim(x) == c(3,4)) >> >> which is really subtle version of his cases >> {But the gut feeling is wrong, as I argue from now on}. > > Personally, I think the problem there is that people forget that == is > vectorised, and for a non-vectorised equality check you really should > use identical: > > stopifnot(identical(dim(x), c(3,4)))identical() is a little pickier than people might think: > identical(dim(matrix(0, 3,4)), c(3,4)) [1] FALSE > identical(dim(matrix(0, 3,4)), c(3L,4L)) [1] TRUE Duncan Murdoch
On Sat, Dec 12, 2015 at 6:08 AM, Hadley Wickham <h.wickham at gmail.com> wrote:> On Sat, Dec 12, 2015 at 3:54 AM, Martin Maechler > <maechler at stat.math.ethz.ch> wrote: >>>>>>> Henrik Bengtsson <henrik.bengtsson at gmail.com> >>>>>>> on Fri, 11 Dec 2015 08:20:55 -0800 writes: >> >> > On Fri, Dec 11, 2015 at 8:10 AM, David Winsemius <dwinsemius at comcast.net> wrote: >> >> >> >>> On Dec 11, 2015, at 5:38 AM, Dario Beraldi <dario.beraldi at gmail.com> wrote: >> >>> >> >>> Hi All, >> >>> >> >>> I'd like to understand the reason why stopifnot(logical(0) == x) doesn't >> >>> (never?) throw an exception, at least in these cases: >> >> >> >> The usual way to test for a length-0 logical object is to use length(): >> >> >> >> x <- logical(0) >> >> >> >> stopifnot( !length(x) & mode(x)=="logical" ) >> >> > I found >> >> > stopifnot(!length(x), mode(x) == "logical") >> >> > more helpful when troubleshooting, because it will tell you whether >> > it's !length(x) or mode(x) == "logical" that is FALSE. It's as if you >> > wrote: >> >> > stopifnot(!length(x)) >> > stopifnot(mode(x) == "logical") >> >> > /Henrik >> >> Yes, indeed, thank you Henrik --- and Jeff Newmiller who's nice >> humorous reply added other relevant points. >> >> As author stopifnot(), I do agree with Dario's "gut feeling" >> that stopifnot() "somehow ought to do the right thing" >> in cases such as >> >> stopifnot(dim(x) == c(3,4)) >> >> which is really subtle version of his cases >> {But the gut feeling is wrong, as I argue from now on}. > > Personally, I think the problem there is that people forget that == is > vectorised, and for a non-vectorised equality check you really should > use identical: > > stopifnot(identical(dim(x), c(3,4)))Kids, this one of the rare cases where you should not listen to Hadley ;) Because,> x <- matrix(1:12, nrow=3, ncol=4) > dim(x)[1] 3 4> identical(dim(x), c(3,4))[1] FALSE Why, because:> storage.mode(dim(x))[1] "integer"> storage.mode(c(3,4))[1] "double" My rule of thumb is that identical() is awesome, but you really have to know the inner bits and pieces (*). When in doubt, use all.equal(), e.g.> all.equal(dim(x), c(3,4))[1] TRUE Related to Hadley's point, is that using all(x == y) is risky because R loops of one of the two vectors if one is longer than the other, e.g.> all(dim(x) == c(3,4))[1] TRUE> all(dim(x) == c(3,4,3,4))[1] TRUE> all(dim(x) == c(3,4,3,4,3,4))[1] TRUE so one really need to check the lengths as well, e.g.> all(length(dim(x)) == length(c(3,4)), dim(x) == c(3,4))[1] TRUE (*) ADVANCED: I would say its risky to use:> identical(dim(x), c(3L,4L))[1] TRUE because, who knows, in a future version of R we might see matrices/arrays that support dimensions longer than .Machine$integer.max which in case dimensions may be stored as doubles. This is what we already have for very long vectors today, cf. help("length"). Henrik> > Hadley > > -- > http://had.co.nz/
>>>>> Hadley Wickham <h.wickham at gmail.com> >>>>> on Sat, 12 Dec 2015 08:08:54 -0600 writes:> On Sat, Dec 12, 2015 at 3:54 AM, Martin Maechler > <maechler at stat.math.ethz.ch> wrote: >>>>>>> Henrik Bengtsson <henrik.bengtsson at gmail.com> on >>>>>>> Fri, 11 Dec 2015 08:20:55 -0800 writes: >> >> > On Fri, Dec 11, 2015 at 8:10 AM, David Winsemius >> <dwinsemius at comcast.net> wrote: >> >> >> >>> On Dec 11, 2015, at 5:38 AM, Dario Beraldi >> <dario.beraldi at gmail.com> wrote: >> >>> >> >>> Hi All, >> >>> >> >>> I'd like to understand the reason why >> stopifnot(logical(0) == x) doesn't >>> (never?) throw an >> exception, at least in these cases: >> >> >> >> The usual way to test for a length-0 logical object is >> to use length(): >> >> >> >> x <- logical(0) >> >> >> >> stopifnot( !length(x) & mode(x)=="logical" ) >> >> > I found >> >> > stopifnot(!length(x), mode(x) == "logical") >> >> > more helpful when troubleshooting, because it will tell >> you whether > it's !length(x) or mode(x) == "logical" >> that is FALSE. It's as if you > wrote: >> >> > stopifnot(!length(x)) > stopifnot(mode(x) == "logical") >> >> > /Henrik >> >> Yes, indeed, thank you Henrik --- and Jeff Newmiller >> who's nice humorous reply added other relevant points. >> >> As author stopifnot(), I do agree with Dario's "gut >> feeling" that stopifnot() "somehow ought to do the right >> thing" in cases such as >> >> stopifnot(dim(x) == c(3,4)) >> >> which is really subtle version of his cases {But the gut >> feeling is wrong, as I argue from now on}. > Personally, I think the problem there is that people > forget that == is vectorised, and for a non-vectorised > equality check you really should use identical: > stopifnot(identical(dim(x), c(3,4))) You are right "in theory" but practice is less easy: identical() tends to be too subtle for many users ... even yourself (;-), not really of course!), Hadley, in the above case: Your stopifnot() would *always* stop, i.e., signal an error because typically all dim() methods return integer, and c(3,4) is double. So, if even Hadley gets it wrong so easily, I wonder if its good to advertize to always use identical() in such cases. I indeed would quite often use identical() in such tests, and you'd too and would quickly find and fix the "trap" of course.. So you are mostly right also in my opinion... Martin
On Sat, Dec 12, 2015 at 1:51 PM, Martin Maechler <maechler at stat.math.ethz.ch> wrote:>>>>>> Hadley Wickham <h.wickham at gmail.com> >>>>>> on Sat, 12 Dec 2015 08:08:54 -0600 writes: > > > On Sat, Dec 12, 2015 at 3:54 AM, Martin Maechler > > <maechler at stat.math.ethz.ch> wrote: > >>>>>>> Henrik Bengtsson <henrik.bengtsson at gmail.com> on > >>>>>>> Fri, 11 Dec 2015 08:20:55 -0800 writes: > >> > >> > On Fri, Dec 11, 2015 at 8:10 AM, David Winsemius > >> <dwinsemius at comcast.net> wrote: > >> >> > >> >>> On Dec 11, 2015, at 5:38 AM, Dario Beraldi > >> <dario.beraldi at gmail.com> wrote: > >> >>> > >> >>> Hi All, > >> >>> > >> >>> I'd like to understand the reason why > >> stopifnot(logical(0) == x) doesn't >>> (never?) throw an > >> exception, at least in these cases: > >> >> > >> >> The usual way to test for a length-0 logical object is > >> to use length(): > >> >> > >> >> x <- logical(0) > >> >> > >> >> stopifnot( !length(x) & mode(x)=="logical" ) > >> > >> > I found > >> > >> > stopifnot(!length(x), mode(x) == "logical") > >> > >> > more helpful when troubleshooting, because it will tell > >> you whether > it's !length(x) or mode(x) == "logical" > >> that is FALSE. It's as if you > wrote: > >> > >> > stopifnot(!length(x)) > stopifnot(mode(x) == "logical") > >> > >> > /Henrik > >> > >> Yes, indeed, thank you Henrik --- and Jeff Newmiller > >> who's nice humorous reply added other relevant points. > >> > >> As author stopifnot(), I do agree with Dario's "gut > >> feeling" that stopifnot() "somehow ought to do the right > >> thing" in cases such as > >> > >> stopifnot(dim(x) == c(3,4)) > >> > >> which is really subtle version of his cases {But the gut > >> feeling is wrong, as I argue from now on}. > > > Personally, I think the problem there is that people > > forget that == is vectorised, and for a non-vectorised > > equality check you really should use identical: > > > stopifnot(identical(dim(x), c(3,4))) > > You are right "in theory" but practice is less easy: > identical() tends to be too subtle for many users ... even > yourself (;-), not really of course!), Hadley, in the above case: > > Your stopifnot() would *always* stop, i.e., signal an error > because typically all dim() methods return integer, and c(3,4) > is double. > So, if even Hadley gets it wrong so easily, I wonder if its good > to advertize to always use identical() in such cases. > I indeed would quite often use identical() in such tests, and > you'd too and would quickly find and fix the "trap" of course.. > So you are mostly right also in my opinion...Ooops, yes - but you would discover this pretty quickly if you weren't coding in a email client ;) I wonder if R is missing an equality operator for this case. Currently: * == is suboptimal because it's vectorised * all.equal is suboptimal because it returns TRUE or a text string * identical is suboptimal because it doesn't do common coercions Do we need another function (equals()?) that uses the same coercion rules as == but isn't vectorised? (Like == it would only work with vectors, so you'd still need identical() for (e.g.) comparing environments) Hadley -- http://had.co.nz/