
12

Yesterday, changes to R's development version were committed, relating
to arithmetic, logic ('&' and '') and
comparison/relational ('<', '==') binary operators
which in NEWS are described as
SIGNIFICANT USERVISIBLE CHANGES:
[.............]
• Arithmetic, logic (‘&’, ‘’) and comparison (aka
‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
behave consistently, notably for arrays of length zero.
Arithmetic between length1 arrays and longer nonarrays had
silently dropped the array attributes and recycled. This
now gives a warning and will signal an error in the future,
as it has always for logic and comparison operations in
these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
‘matrix(1,1) < 2:3’).
As the above "visually suggests" one could think of the changes
falling mainly two groups,
1) <0extent array> (op) <nonarray>
2) <1extent array> (arith) <nonarray of length != 1>
These changes are partly nonback compatible and may break
existing code. We believe that the internal consistency gained
from the changes is worth the few places with problems.
We expect some package maintainers (1020, or even more?) need
to adapt their code.
Case '2)' above mainly results in a new warning, e.g.,
> matrix(1,1) + 1:2
[1] 2 3
Warning message:
In matrix(1, 1) + 1:2 :
dropping dim() of array of length one. Will become ERROR
>
whereas '1)' gives errors in cases the result silently was a
vector of length zero, or also keeps array (dim & dimnames) in
cases these were silently dropped.
The following is a "heavily" commented R script showing (all ?)
the important cases with changes :

(m < cbind(a=1[0], b=2[0]))
Lm < m; storage.mode(Lm) < "logical"
Im < m; storage.mode(Im) < "integer"
## 1. 
try( m & NULL ) # in R <= 3.3.x :
## Error in m & NULL :
## operations are possible only for numeric, logical or complex types
##
## gives 'Lm' in R >= 3.4.0
## 2. 
m + 2:3 ## gave numeric(0), now remains matrix identical to m
Im + 2:3 ## gave integer(0), now remains matrix identical to Im (integer)
m > 1 ## gave logical(0), now remains matrix identical to Lm (logical)
m > 0.1[0] ## ditto
m > NULL ## ditto
## 3. 
mm < m[,c(1:2,2:1,2)]
try( m == mm ) ## now gives error "nonconformable arrays",
## but gave logical(0) in R <= 3.3.x
## 4. 
str( Im + NULL) ## gave "num", now gives "int"
## 5. 
## special case for arithmetic w/ length1 array
(m1 < matrix(1,1,1, dimnames=list("Ro","col")))
(m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match the length of object [2]
tools::assertError(m1 < 1:2)# ERR: (ditto)
##
## non0length arrays combined with {NULL or double() or ...} *fail*
### Length1 arrays: Arithmetic with vectors > 1 treated array as scalar
m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/ warning to "be ERROR"
try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error* now in R >= 3.4.0
tools::assertError(m1 & NULL) # gave and gives error
tools::assertError(m1  double())# ditto
## m2 was slightly different:
tools::assertError(m2 + NULL)
tools::assertError(m2 & NULL)
try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as above!

Note that in R's own 'nls' sources, there was one case of
situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
In such cases, you should explicitly coerce it to a vector,
either ("selfexplainingly") by as.vector(.), or as I did in
the nls case by c(.) : The latter is much less
selfexplaining, but nicer to read in mathematical formulae, and
currently also more efficient because it is a .Primitive.
Please use Rdevel with your code, and let us know if you see
effects that seem adverse.
In some case where Rdevel now gives an error but did not
previously, we could contemplate giving another "warning
.... 'to become ERROR'" if there was too much breakage, though
I don't expect that.
For the R Core Team,
Martin Maechler,
ETH Zurich
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Martin Maechler < [hidden email]>
>>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
> Yesterday, changes to R's development version were committed, relating
> to arithmetic, logic ('&' and '') and
> comparison/relational ('<', '==') binary operators
> which in NEWS are described as
> SIGNIFICANT USERVISIBLE CHANGES:
> [.............]
> • Arithmetic, logic (‘&’, ‘’) and comparison (aka
> ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
> behave consistently, notably for arrays of length zero.
> Arithmetic between length1 arrays and longer nonarrays had
> silently dropped the array attributes and recycled. This
> now gives a warning and will signal an error in the future,
> as it has always for logic and comparison operations in
> these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
> ‘matrix(1,1) < 2:3’).
> As the above "visually suggests" one could think of the changes
> falling mainly two groups,
> 1) <0extent array> (op) <nonarray>
> 2) <1extent array> (arith) <nonarray of length != 1>
> These changes are partly nonback compatible and may break
> existing code. We believe that the internal consistency gained
> from the changes is worth the few places with problems.
> We expect some package maintainers (1020, or even more?) need
> to adapt their code.
> Case '2)' above mainly results in a new warning, e.g.,
>> matrix(1,1) + 1:2
> [1] 2 3
> Warning message:
> In matrix(1, 1) + 1:2 :
> dropping dim() of array of length one. Will become ERROR
>>
> whereas '1)' gives errors in cases the result silently was a
> vector of length zero, or also keeps array (dim & dimnames) in
> cases these were silently dropped.
> The following is a "heavily" commented R script showing (all ?)
> the important cases with changes :
> 
> (m < cbind(a=1[0], b=2[0]))
> Lm < m; storage.mode(Lm) < "logical"
> Im < m; storage.mode(Im) < "integer"
> ## 1. 
> try( m & NULL ) # in R <= 3.3.x :
> ## Error in m & NULL :
> ## operations are possible only for numeric, logical or complex types
> ##
> ## gives 'Lm' in R >= 3.4.0
> ## 2. 
> m + 2:3 ## gave numeric(0), now remains matrix identical to m
> Im + 2:3 ## gave integer(0), now remains matrix identical to Im (integer)
> m > 1 ## gave logical(0), now remains matrix identical to Lm (logical)
> m > 0.1[0] ## ditto
> m > NULL ## ditto
> ## 3. 
> mm < m[,c(1:2,2:1,2)]
> try( m == mm ) ## now gives error "nonconformable arrays",
> ## but gave logical(0) in R <= 3.3.x
> ## 4. 
> str( Im + NULL) ## gave "num", now gives "int"
> ## 5. 
> ## special case for arithmetic w/ length1 array
> (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
> (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
> m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
> tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match the length of object [2]
> tools::assertError(m1 < 1:2)# ERR: (ditto)
> ##
> ## non0length arrays combined with {NULL or double() or ...} *fail*
> ### Length1 arrays: Arithmetic with vectors > 1 treated array as scalar
> m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/ warning to "be ERROR"
> try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error* now in R >= 3.4.0
> tools::assertError(m1 & NULL) # gave and gives error
> tools::assertError(m1  double())# ditto
> ## m2 was slightly different:
> tools::assertError(m2 + NULL)
> tools::assertError(m2 & NULL)
> try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as above!
> 
> Note that in R's own 'nls' sources, there was one case of
> situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
> In such cases, you should explicitly coerce it to a vector,
> either ("selfexplainingly") by as.vector(.), or as I did in
> the nls case by c(.) : The latter is much less
> selfexplaining, but nicer to read in mathematical formulae, and
> currently also more efficient because it is a .Primitive.
> Please use Rdevel with your code, and let us know if you see
> effects that seem adverse.
I've been slightly surprised (or even "frustrated") by the empty
reaction on our Rdevel list to this post.
I would have expected some critique, may be even some praise,
... in any case some sign people are "thinking along" (as we say
in German).
In the mean time, I've actually thought along the one case which
is last above: The <op> (binary operation) between a
non0length array and a 0length vector (and NULL which should
be treated like a 0length vector):
R <= 3.3.1 *is* quite inconsistent with these:
and my proposal above (implemented in Rdevel, since Sep.5) would give an
error for all these, but instead, R really could be more lenient here:
A 0length result is ok, and it should *not* inherit the array
(dim, dimnames), since the array is not of length 0. So instead
of the above [for the very last part only!!], we would aim for
the following. These *all* give an error in current Rdevel,
with the exception of 'm1 + NULL' which "only" gives a "bad
warning" :

m1 < matrix(1,1)
m2 < matrix(1,2)
m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
try(m1  double())# ERROR in R <= 3.3.x > change to logical(0) ?!
## m2 slightly different:
try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
m2 == NULL # logical(0) in R <= 3.3.x > OK ?!

This would be slightly more backcompatible than the currently
implemented proposal. Everything else I said remains true, and
I'm pretty sure most changes needed in packages would remain to be done.
Opinions ?
> In some case where Rdevel now gives an error but did not
> previously, we could contemplate giving another "warning
> .... 'to become ERROR'" if there was too much breakage, though
> I don't expect that.
> For the R Core Team,
> Martin Maechler,
> ETH Zurich
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Martin Maechler < [hidden email]>
>>>>> on Wed, 7 Sep 2016 11:49:11 +0200 writes:
>>>>> Martin Maechler < [hidden email]>
>>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>> Yesterday, changes to R's development version were committed, relating
>> to arithmetic, logic ('&' and '') and
>> comparison/relational ('<', '==') binary operators
>> which in NEWS are described as
>> SIGNIFICANT USERVISIBLE CHANGES:
>> [.............]
>> • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>> ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>> behave consistently, notably for arrays of length zero.
>> Arithmetic between length1 arrays and longer nonarrays had
>> silently dropped the array attributes and recycled. This
>> now gives a warning and will signal an error in the future,
>> as it has always for logic and comparison operations in
>> these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>> ‘matrix(1,1) < 2:3’).
>> As the above "visually suggests" one could think of the changes
>> falling mainly two groups,
>> 1) <0extent array> (op) <nonarray>
>> 2) <1extent array> (arith) <nonarray of length != 1>
>> These changes are partly nonback compatible and may break
>> existing code. We believe that the internal consistency gained
>> from the changes is worth the few places with problems.
>> We expect some package maintainers (1020, or even more?) need
>> to adapt their code.
>> Case '2)' above mainly results in a new warning, e.g.,
>>> matrix(1,1) + 1:2
>> [1] 2 3
>> Warning message:
>> In matrix(1, 1) + 1:2 :
>> dropping dim() of array of length one. Will become ERROR
>>>
>> whereas '1)' gives errors in cases the result silently was a
>> vector of length zero, or also keeps array (dim & dimnames) in
>> cases these were silently dropped.
>> The following is a "heavily" commented R script showing (all ?)
>> the important cases with changes :
>> 
>> (m < cbind(a=1[0], b=2[0]))
>> Lm < m; storage.mode(Lm) < "logical"
>> Im < m; storage.mode(Im) < "integer"
>> ## 1. 
>> try( m & NULL ) # in R <= 3.3.x :
>> ## Error in m & NULL :
>> ## operations are possible only for numeric, logical or complex types
>> ##
>> ## gives 'Lm' in R >= 3.4.0
>> ## 2. 
>> m + 2:3 ## gave numeric(0), now remains matrix identical to m
>> Im + 2:3 ## gave integer(0), now remains matrix identical to Im (integer)
>> m > 1 ## gave logical(0), now remains matrix identical to Lm (logical)
>> m > 0.1[0] ## ditto
>> m > NULL ## ditto
>> ## 3. 
>> mm < m[,c(1:2,2:1,2)]
>> try( m == mm ) ## now gives error "nonconformable arrays",
>> ## but gave logical(0) in R <= 3.3.x
>> ## 4. 
>> str( Im + NULL) ## gave "num", now gives "int"
>> ## 5. 
>> ## special case for arithmetic w/ length1 array
>> (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>> (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>> m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>> tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match the length of object [2]
>> tools::assertError(m1 < 1:2)# ERR: (ditto)
>> ##
>> ## non0length arrays combined with {NULL or double() or ...} *fail*
>> ### Length1 arrays: Arithmetic with vectors > 1 treated array as scalar
>> m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/ warning to "be ERROR"
>> try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error* now in R >= 3.4.0
>> tools::assertError(m1 & NULL) # gave and gives error
>> tools::assertError(m1  double())# ditto
>> ## m2 was slightly different:
>> tools::assertError(m2 + NULL)
>> tools::assertError(m2 & NULL)
>> try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as above!
>> 
>> Note that in R's own 'nls' sources, there was one case of
>> situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
>> In such cases, you should explicitly coerce it to a vector,
>> either ("selfexplainingly") by as.vector(.), or as I did in
>> the nls case by c(.) : The latter is much less
>> selfexplaining, but nicer to read in mathematical formulae, and
>> currently also more efficient because it is a .Primitive.
>> Please use Rdevel with your code, and let us know if you see
>> effects that seem adverse.
> I've been slightly surprised (or even "frustrated") by the empty
> reaction on our Rdevel list to this post.
> I would have expected some critique, may be even some praise,
> ... in any case some sign people are "thinking along" (as we say
> in German).
> In the mean time, I've actually thought along the one case which
> is last above: The <op> (binary operation) between a
> non0length array and a 0length vector (and NULL which should
> be treated like a 0length vector):
> R <= 3.3.1 *is* quite inconsistent with these:
> and my proposal above (implemented in Rdevel, since Sep.5) would give an
> error for all these, but instead, R really could be more lenient here:
> A 0length result is ok, and it should *not* inherit the array
> (dim, dimnames), since the array is not of length 0. So instead
> of the above [for the very last part only!!], we would aim for
> the following. These *all* give an error in current Rdevel,
> with the exception of 'm1 + NULL' which "only" gives a "bad
> warning" :
> 
> m1 < matrix(1,1)
> m2 < matrix(1,2)
> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0) ?!
> ## m2 slightly different:
> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
> 
> This would be slightly more backcompatible than the currently
> implemented proposal. Everything else I said remains true, and
> I'm pretty sure most changes needed in packages would remain to be done.
> Opinions ?
I now have updated 'Rdevel' so it *does* implement the above
small amendment to the original proposal.
As a consequence, to *cumulative* changes are slightly more back
compatible.
If you are interested in this topic .. or if your CRAN package
checks show recent problems on the 'CRAN checks' web page,
make sure you get an Rdevel version with svn rev. 71222 or
newer.
Martin
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Martin
I'd like to make a comment; I think that R's behaviour on 'edge' cases like
this is an important thing and it's great that you are working on it.
I make heavy use of zeroextent arrays, chiefly because the dimnames are an
efficient and logical way to keep track of certain types of information.
If I have, for example,
a < array(0,c(2,0,2))
dimnames(a) < list(name=c('Mike','Kevin'),NULL,item=c("hat","scarf"))
Then in R3.3.1, 70800 I get
> a>0
logical(0)
>
But in 71219 I get
> a>0
, , item = hat
name
Mike
Kevin
, , item = scarf
name
Mike
Kevin
(which is an empty logical array that holds the names of the people and
their clothes). I find the behaviour of 71219 very much preferable because
there is no reason to discard the information in the dimnames.
Best wishes
Robin
On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler < [hidden email]>
wrote:
> >>>>> Martin Maechler < [hidden email]>
> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>
> > Yesterday, changes to R's development version were committed,
> relating
> > to arithmetic, logic ('&' and '') and
> > comparison/relational ('<', '==') binary operators
> > which in NEWS are described as
>
> > SIGNIFICANT USERVISIBLE CHANGES:
>
> > [.............]
>
> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
> > behave consistently, notably for arrays of length zero.
>
> > Arithmetic between length1 arrays and longer nonarrays had
> > silently dropped the array attributes and recycled. This
> > now gives a warning and will signal an error in the future,
> > as it has always for logic and comparison operations in
> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
> > ‘matrix(1,1) < 2:3’).
>
> > As the above "visually suggests" one could think of the changes
> > falling mainly two groups,
> > 1) <0extent array> (op) <nonarray>
> > 2) <1extent array> (arith) <nonarray of length != 1>
>
> > These changes are partly nonback compatible and may break
> > existing code. We believe that the internal consistency gained
> > from the changes is worth the few places with problems.
>
> > We expect some package maintainers (1020, or even more?) need
> > to adapt their code.
>
> > Case '2)' above mainly results in a new warning, e.g.,
>
> >> matrix(1,1) + 1:2
> > [1] 2 3
> > Warning message:
> > In matrix(1, 1) + 1:2 :
> > dropping dim() of array of length one. Will become ERROR
> >>
>
> > whereas '1)' gives errors in cases the result silently was a
> > vector of length zero, or also keeps array (dim & dimnames) in
> > cases these were silently dropped.
>
> > The following is a "heavily" commented R script showing (all ?)
> > the important cases with changes :
>
> > 
> 
>
> > (m < cbind(a=1[0], b=2[0]))
> > Lm < m; storage.mode(Lm) < "logical"
> > Im < m; storage.mode(Im) < "integer"
>
> > ## 1. 
> > try( m & NULL ) # in R <= 3.3.x :
> > ## Error in m & NULL :
> > ## operations are possible only for numeric, logical or complex
> types
> > ##
> > ## gives 'Lm' in R >= 3.4.0
>
> > ## 2. 
> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
> (integer)
>
> > m > 1 ## gave logical(0), now remains matrix identical to Lm
> (logical)
> > m > 0.1[0] ## ditto
> > m > NULL ## ditto
>
> > ## 3. 
> > mm < m[,c(1:2,2:1,2)]
> > try( m == mm ) ## now gives error "nonconformable arrays",
> > ## but gave logical(0) in R <= 3.3.x
>
> > ## 4. 
> > str( Im + NULL) ## gave "num", now gives "int"
>
> > ## 5. 
> > ## special case for arithmetic w/ length1 array
> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>
> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match the
> length of object [2]
> > tools::assertError(m1 < 1:2)# ERR: (ditto)
> > ##
> > ## non0length arrays combined with {NULL or double() or ...} *fail*
>
> > ### Length1 arrays: Arithmetic with vectors > 1 treated array
> as scalar
> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
> warning to "be ERROR"
> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error*
> now in R >= 3.4.0
> > tools::assertError(m1 & NULL) # gave and gives error
> > tools::assertError(m1  double())# ditto
> > ## m2 was slightly different:
> > tools::assertError(m2 + NULL)
> > tools::assertError(m2 & NULL)
> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as above!
>
> > 
> 
>
>
> > Note that in R's own 'nls' sources, there was one case of
> > situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
>
> > In such cases, you should explicitly coerce it to a vector,
> > either ("selfexplainingly") by as.vector(.), or as I did in
> > the nls case by c(.) : The latter is much less
> > selfexplaining, but nicer to read in mathematical formulae, and
> > currently also more efficient because it is a .Primitive.
>
> > Please use Rdevel with your code, and let us know if you see
> > effects that seem adverse.
>
> I've been slightly surprised (or even "frustrated") by the empty
> reaction on our Rdevel list to this post.
>
> I would have expected some critique, may be even some praise,
> ... in any case some sign people are "thinking along" (as we say
> in German).
>
> In the mean time, I've actually thought along the one case which
> is last above: The <op> (binary operation) between a
> non0length array and a 0length vector (and NULL which should
> be treated like a 0length vector):
>
> R <= 3.3.1 *is* quite inconsistent with these:
>
>
> and my proposal above (implemented in Rdevel, since Sep.5) would give an
> error for all these, but instead, R really could be more lenient here:
> A 0length result is ok, and it should *not* inherit the array
> (dim, dimnames), since the array is not of length 0. So instead
> of the above [for the very last part only!!], we would aim for
> the following. These *all* give an error in current Rdevel,
> with the exception of 'm1 + NULL' which "only" gives a "bad
> warning" :
>
> 
>
> m1 < matrix(1,1)
> m2 < matrix(1,2)
>
> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0) ?!
> ## m2 slightly different:
> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>
> 
>
> This would be slightly more backcompatible than the currently
> implemented proposal. Everything else I said remains true, and
> I'm pretty sure most changes needed in packages would remain to be done.
>
> Opinions ?
>
>
>
> > In some case where Rdevel now gives an error but did not
> > previously, we could contemplate giving another "warning
> > .... 'to become ERROR'" if there was too much breakage, though
> > I don't expect that.
>
>
> > For the R Core Team,
>
> > Martin Maechler,
> > ETH Zurich
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel>

Robin Hankin
Neutral theorist
[hidden email]
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


+1. Very grateful; more consistency is always great :)
On Wednesday, 7 September 2016, robin hankin < [hidden email]> wrote:
> Martin
>
> I'd like to make a comment; I think that R's behaviour on 'edge' cases like
> this is an important thing and it's great that you are working on it.
>
> I make heavy use of zeroextent arrays, chiefly because the dimnames are an
> efficient and logical way to keep track of certain types of information.
>
> If I have, for example,
>
> a < array(0,c(2,0,2))
> dimnames(a) < list(name=c('Mike','Kevin'),NULL,item=c("hat","scarf"))
>
>
> Then in R3.3.1, 70800 I get
>
> > a>0
> logical(0)
> >
>
> But in 71219 I get
>
> > a>0
> , , item = hat
>
>
> name
> Mike
> Kevin
>
> , , item = scarf
>
>
> name
> Mike
> Kevin
>
> (which is an empty logical array that holds the names of the people and
> their clothes). I find the behaviour of 71219 very much preferable because
> there is no reason to discard the information in the dimnames.
>
>
> Best wishes
>
> Robin
>
>
>
>
> On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
> [hidden email] <javascript:;>>
> wrote:
>
> > >>>>> Martin Maechler < [hidden email] <javascript:;>>
> > >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
> >
> > > Yesterday, changes to R's development version were committed,
> > relating
> > > to arithmetic, logic ('&' and '') and
> > > comparison/relational ('<', '==') binary operators
> > > which in NEWS are described as
> >
> > > SIGNIFICANT USERVISIBLE CHANGES:
> >
> > > [.............]
> >
> > > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
> > > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
> > > behave consistently, notably for arrays of length zero.
> >
> > > Arithmetic between length1 arrays and longer nonarrays had
> > > silently dropped the array attributes and recycled. This
> > > now gives a warning and will signal an error in the future,
> > > as it has always for logic and comparison operations in
> > > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
> > > ‘matrix(1,1) < 2:3’).
> >
> > > As the above "visually suggests" one could think of the changes
> > > falling mainly two groups,
> > > 1) <0extent array> (op) <nonarray>
> > > 2) <1extent array> (arith) <nonarray of length != 1>
> >
> > > These changes are partly nonback compatible and may break
> > > existing code. We believe that the internal consistency gained
> > > from the changes is worth the few places with problems.
> >
> > > We expect some package maintainers (1020, or even more?) need
> > > to adapt their code.
> >
> > > Case '2)' above mainly results in a new warning, e.g.,
> >
> > >> matrix(1,1) + 1:2
> > > [1] 2 3
> > > Warning message:
> > > In matrix(1, 1) + 1:2 :
> > > dropping dim() of array of length one. Will become ERROR
> > >>
> >
> > > whereas '1)' gives errors in cases the result silently was a
> > > vector of length zero, or also keeps array (dim & dimnames) in
> > > cases these were silently dropped.
> >
> > > The following is a "heavily" commented R script showing (all ?)
> > > the important cases with changes :
> >
> > > 
> > 
> >
> > > (m < cbind(a=1[0], b=2[0]))
> > > Lm < m; storage.mode(Lm) < "logical"
> > > Im < m; storage.mode(Im) < "integer"
> >
> > > ## 1. 
> > > try( m & NULL ) # in R <= 3.3.x :
> > > ## Error in m & NULL :
> > > ## operations are possible only for numeric, logical or complex
> > types
> > > ##
> > > ## gives 'Lm' in R >= 3.4.0
> >
> > > ## 2. 
> > > m + 2:3 ## gave numeric(0), now remains matrix identical to m
> > > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
> > (integer)
> >
> > > m > 1 ## gave logical(0), now remains matrix identical to Lm
> > (logical)
> > > m > 0.1[0] ## ditto
> > > m > NULL ## ditto
> >
> > > ## 3. 
> > > mm < m[,c(1:2,2:1,2)]
> > > try( m == mm ) ## now gives error "nonconformable arrays",
> > > ## but gave logical(0) in R <= 3.3.x
> >
> > > ## 4. 
> > > str( Im + NULL) ## gave "num", now gives "int"
> >
> > > ## 5. 
> > > ## special case for arithmetic w/ length1 array
> > > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
> > > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
> >
> > > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
> > > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match
> the
> > length of object [2]
> > > tools::assertError(m1 < 1:2)# ERR: (ditto)
> > > ##
> > > ## non0length arrays combined with {NULL or double() or ...}
> *fail*
> >
> > > ### Length1 arrays: Arithmetic with vectors > 1 treated array
> > as scalar
> > > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
> > warning to "be ERROR"
> > > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error*
> > now in R >= 3.4.0
> > > tools::assertError(m1 & NULL) # gave and gives error
> > > tools::assertError(m1  double())# ditto
> > > ## m2 was slightly different:
> > > tools::assertError(m2 + NULL)
> > > tools::assertError(m2 & NULL)
> > > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
> above!
> >
> > > 
> > 
> >
> >
> > > Note that in R's own 'nls' sources, there was one case of
> > > situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
> >
> > > In such cases, you should explicitly coerce it to a vector,
> > > either ("selfexplainingly") by as.vector(.), or as I did in
> > > the nls case by c(.) : The latter is much less
> > > selfexplaining, but nicer to read in mathematical formulae, and
> > > currently also more efficient because it is a .Primitive.
> >
> > > Please use Rdevel with your code, and let us know if you see
> > > effects that seem adverse.
> >
> > I've been slightly surprised (or even "frustrated") by the empty
> > reaction on our Rdevel list to this post.
> >
> > I would have expected some critique, may be even some praise,
> > ... in any case some sign people are "thinking along" (as we say
> > in German).
> >
> > In the mean time, I've actually thought along the one case which
> > is last above: The <op> (binary operation) between a
> > non0length array and a 0length vector (and NULL which should
> > be treated like a 0length vector):
> >
> > R <= 3.3.1 *is* quite inconsistent with these:
> >
> >
> > and my proposal above (implemented in Rdevel, since Sep.5) would give an
> > error for all these, but instead, R really could be more lenient here:
> > A 0length result is ok, and it should *not* inherit the array
> > (dim, dimnames), since the array is not of length 0. So instead
> > of the above [for the very last part only!!], we would aim for
> > the following. These *all* give an error in current Rdevel,
> > with the exception of 'm1 + NULL' which "only" gives a "bad
> > warning" :
> >
> > 
> >
> > m1 < matrix(1,1)
> > m2 < matrix(1,2)
> >
> > m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
> > m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
> > try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> > try(m1  double())# ERROR in R <= 3.3.x > change to logical(0) ?!
> > ## m2 slightly different:
> > try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
> > try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> > m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
> >
> > 
> >
> > This would be slightly more backcompatible than the currently
> > implemented proposal. Everything else I said remains true, and
> > I'm pretty sure most changes needed in packages would remain to be done.
> >
> > Opinions ?
> >
> >
> >
> > > In some case where Rdevel now gives an error but did not
> > > previously, we could contemplate giving another "warning
> > > .... 'to become ERROR'" if there was too much breakage, though
> > > I don't expect that.
> >
> >
> > > For the R Core Team,
> >
> > > Martin Maechler,
> > > ETH Zurich
> >
> > ______________________________________________
> > [hidden email] <javascript:;> mailing list
> > https://stat.ethz.ch/mailman/listinfo/rdevel> >
>
>
>
> 
> Robin Hankin
> Neutral theorist
> [hidden email] <javascript:;>
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] <javascript:;> mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> robin hankin < [hidden email]>
>>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
> Martin I'd like to make a comment; I think that R's
> behaviour on 'edge' cases like this is an important thing
> and it's great that you are working on it.
> I make heavy use of zeroextent arrays, chiefly because
> the dimnames are an efficient and logical way to keep
> track of certain types of information.
> If I have, for example,
> a < array(0,c(2,0,2))
> dimnames(a) < list(name=c('Mike','Kevin'),NULL,item=c("hat","scarf"))
> Then in R3.3.1, 70800 I get
a> 0
> logical(0)
>>
> But in 71219 I get
a> 0
> , , item = hat
> name
> Mike
> Kevin
> , , item = scarf
> name
> Mike
> Kevin
> (which is an empty logical array that holds the names of the people and
> their clothes). I find the behaviour of 71219 very much preferable because
> there is no reason to discard the information in the dimnames.
Thanks a lot, Robin, (and Oliver) !
Yes, the above is such a case where the new behavior makes much sense.
And this behavior remains identical after the 71222 amendment.
Martin
> Best wishes
> Robin
> On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler < [hidden email]>
> wrote:
>> >>>>> Martin Maechler < [hidden email]>
>> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>
>> > Yesterday, changes to R's development version were committed,
>> relating
>> > to arithmetic, logic ('&' and '') and
>> > comparison/relational ('<', '==') binary operators
>> > which in NEWS are described as
>>
>> > SIGNIFICANT USERVISIBLE CHANGES:
>>
>> > [.............]
>>
>> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>> > behave consistently, notably for arrays of length zero.
>>
>> > Arithmetic between length1 arrays and longer nonarrays had
>> > silently dropped the array attributes and recycled. This
>> > now gives a warning and will signal an error in the future,
>> > as it has always for logic and comparison operations in
>> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>> > ‘matrix(1,1) < 2:3’).
>>
>> > As the above "visually suggests" one could think of the changes
>> > falling mainly two groups,
>> > 1) <0extent array> (op) <nonarray>
>> > 2) <1extent array> (arith) <nonarray of length != 1>
>>
>> > These changes are partly nonback compatible and may break
>> > existing code. We believe that the internal consistency gained
>> > from the changes is worth the few places with problems.
>>
>> > We expect some package maintainers (1020, or even more?) need
>> > to adapt their code.
>>
>> > Case '2)' above mainly results in a new warning, e.g.,
>>
>> >> matrix(1,1) + 1:2
>> > [1] 2 3
>> > Warning message:
>> > In matrix(1, 1) + 1:2 :
>> > dropping dim() of array of length one. Will become ERROR
>> >>
>>
>> > whereas '1)' gives errors in cases the result silently was a
>> > vector of length zero, or also keeps array (dim & dimnames) in
>> > cases these were silently dropped.
>>
>> > The following is a "heavily" commented R script showing (all ?)
>> > the important cases with changes :
>>
>> > 
>> 
>>
>> > (m < cbind(a=1[0], b=2[0]))
>> > Lm < m; storage.mode(Lm) < "logical"
>> > Im < m; storage.mode(Im) < "integer"
>>
>> > ## 1. 
>> > try( m & NULL ) # in R <= 3.3.x :
>> > ## Error in m & NULL :
>> > ## operations are possible only for numeric, logical or complex
>> types
>> > ##
>> > ## gives 'Lm' in R >= 3.4.0
>>
>> > ## 2. 
>> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
>> (integer)
>>
>> > m > 1 ## gave logical(0), now remains matrix identical to Lm
>> (logical)
>> > m > 0.1[0] ## ditto
>> > m > NULL ## ditto
>>
>> > ## 3. 
>> > mm < m[,c(1:2,2:1,2)]
>> > try( m == mm ) ## now gives error "nonconformable arrays",
>> > ## but gave logical(0) in R <= 3.3.x
>>
>> > ## 4. 
>> > str( Im + NULL) ## gave "num", now gives "int"
>>
>> > ## 5. 
>> > ## special case for arithmetic w/ length1 array
>> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>
>> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match the
>> length of object [2]
>> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>> > ##
>> > ## non0length arrays combined with {NULL or double() or ...} *fail*
>>
>> > ### Length1 arrays: Arithmetic with vectors > 1 treated array
>> as scalar
>> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>> warning to "be ERROR"
>> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error*
>> now in R >= 3.4.0
>> > tools::assertError(m1 & NULL) # gave and gives error
>> > tools::assertError(m1  double())# ditto
>> > ## m2 was slightly different:
>> > tools::assertError(m2 + NULL)
>> > tools::assertError(m2 & NULL)
>> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as above!
>>
>> > 
>> 
>>
>>
>> > Note that in R's own 'nls' sources, there was one case of
>> > situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
>>
>> > In such cases, you should explicitly coerce it to a vector,
>> > either ("selfexplainingly") by as.vector(.), or as I did in
>> > the nls case by c(.) : The latter is much less
>> > selfexplaining, but nicer to read in mathematical formulae, and
>> > currently also more efficient because it is a .Primitive.
>>
>> > Please use Rdevel with your code, and let us know if you see
>> > effects that seem adverse.
>>
>> I've been slightly surprised (or even "frustrated") by the empty
>> reaction on our Rdevel list to this post.
>>
>> I would have expected some critique, may be even some praise,
>> ... in any case some sign people are "thinking along" (as we say
>> in German).
>>
>> In the mean time, I've actually thought along the one case which
>> is last above: The <op> (binary operation) between a
>> non0length array and a 0length vector (and NULL which should
>> be treated like a 0length vector):
>>
>> R <= 3.3.1 *is* quite inconsistent with these:
>>
>>
>> and my proposal above (implemented in Rdevel, since Sep.5) would give an
>> error for all these, but instead, R really could be more lenient here:
>> A 0length result is ok, and it should *not* inherit the array
>> (dim, dimnames), since the array is not of length 0. So instead
>> of the above [for the very last part only!!], we would aim for
>> the following. These *all* give an error in current Rdevel,
>> with the exception of 'm1 + NULL' which "only" gives a "bad
>> warning" :
>>
>> 
>>
>> m1 < matrix(1,1)
>> m2 < matrix(1,2)
>>
>> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
>> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0) ?!
>> ## m2 slightly different:
>> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
>> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
>> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>
>> 
>>
>> This would be slightly more backcompatible than the currently
>> implemented proposal. Everything else I said remains true, and
>> I'm pretty sure most changes needed in packages would remain to be done.
>>
>> Opinions ?
>>
>>
>>
>> > In some case where Rdevel now gives an error but did not
>> > previously, we could contemplate giving another "warning
>> > .... 'to become ERROR'" if there was too much breakage, though
>> > I don't expect that.
>>
>>
>> > For the R Core Team,
>>
>> > Martin Maechler,
>> > ETH Zurich
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel >>
> 
> Robin Hankin
> Neutral theorist
> [hidden email]
> [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Martin,
Like Robin and Oliver I think this type of edgecase consistency is
important and that it's fantastic that Rcore  and you personally  are
willing to tackle some of these "gotcha" behaviors. "Little" stuff like
this really does combine to go a long way to making R better and better.
I do wonder a bit about the
x = 1:2
y = NULL
x < y
case.
Returning a logical of length 0 is more backwards compatible, but is it
ever what the author actually intended? I have trouble thinking of a case
where that lessthan didn't carry an implicit assumption that y was
nonNULL. I can say that in my own code, I've never hit that behavior in a
case that wasn't an error.
My vote (unless someone else points out a compelling use for the behavior)
is for the to throw an error. As a developer, I'd rather things like this
break so the bug in my logic is visible, rather than propagating as the
0length logical is &'ed or 'ed with other logical vectors, or used to
subset, or (in the case it should be length 1) passed to if() (if throws an
error now, but the rest would silently "work").
Best,
~G
On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler < [hidden email]>
wrote:
> >>>>> robin hankin < [hidden email]>
> >>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>
> > Martin I'd like to make a comment; I think that R's
> > behaviour on 'edge' cases like this is an important thing
> > and it's great that you are working on it.
>
> > I make heavy use of zeroextent arrays, chiefly because
> > the dimnames are an efficient and logical way to keep
> > track of certain types of information.
>
> > If I have, for example,
>
> > a < array(0,c(2,0,2))
> > dimnames(a) < list(name=c('Mike','Kevin'),
> NULL,item=c("hat","scarf"))
>
>
> > Then in R3.3.1, 70800 I get
>
> a> 0
> > logical(0)
> >>
>
> > But in 71219 I get
>
> a> 0
> > , , item = hat
>
>
> > name
> > Mike
> > Kevin
>
> > , , item = scarf
>
>
> > name
> > Mike
> > Kevin
>
> > (which is an empty logical array that holds the names of the people
> and
> > their clothes). I find the behaviour of 71219 very much preferable
> because
> > there is no reason to discard the information in the dimnames.
>
> Thanks a lot, Robin, (and Oliver) !
>
> Yes, the above is such a case where the new behavior makes much sense.
> And this behavior remains identical after the 71222 amendment.
>
> Martin
>
> > Best wishes
> > Robin
>
>
>
>
> > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
> [hidden email]>
> > wrote:
>
> >> >>>>> Martin Maechler < [hidden email]>
> >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
> >>
> >> > Yesterday, changes to R's development version were committed,
> >> relating
> >> > to arithmetic, logic ('&' and '') and
> >> > comparison/relational ('<', '==') binary operators
> >> > which in NEWS are described as
> >>
> >> > SIGNIFICANT USERVISIBLE CHANGES:
> >>
> >> > [.............]
> >>
> >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
> >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
> >> > behave consistently, notably for arrays of length zero.
> >>
> >> > Arithmetic between length1 arrays and longer nonarrays had
> >> > silently dropped the array attributes and recycled. This
> >> > now gives a warning and will signal an error in the future,
> >> > as it has always for logic and comparison operations in
> >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
> >> > ‘matrix(1,1) < 2:3’).
> >>
> >> > As the above "visually suggests" one could think of the changes
> >> > falling mainly two groups,
> >> > 1) <0extent array> (op) <nonarray>
> >> > 2) <1extent array> (arith) <nonarray of length != 1>
> >>
> >> > These changes are partly nonback compatible and may break
> >> > existing code. We believe that the internal consistency gained
> >> > from the changes is worth the few places with problems.
> >>
> >> > We expect some package maintainers (1020, or even more?) need
> >> > to adapt their code.
> >>
> >> > Case '2)' above mainly results in a new warning, e.g.,
> >>
> >> >> matrix(1,1) + 1:2
> >> > [1] 2 3
> >> > Warning message:
> >> > In matrix(1, 1) + 1:2 :
> >> > dropping dim() of array of length one. Will become ERROR
> >> >>
> >>
> >> > whereas '1)' gives errors in cases the result silently was a
> >> > vector of length zero, or also keeps array (dim & dimnames) in
> >> > cases these were silently dropped.
> >>
> >> > The following is a "heavily" commented R script showing (all ?)
> >> > the important cases with changes :
> >>
> >> > 
> >> 
> >>
> >> > (m < cbind(a=1[0], b=2[0]))
> >> > Lm < m; storage.mode(Lm) < "logical"
> >> > Im < m; storage.mode(Im) < "integer"
> >>
> >> > ## 1. 
> >> > try( m & NULL ) # in R <= 3.3.x :
> >> > ## Error in m & NULL :
> >> > ## operations are possible only for numeric, logical or complex
> >> types
> >> > ##
> >> > ## gives 'Lm' in R >= 3.4.0
> >>
> >> > ## 2. 
> >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
> >> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
> >> (integer)
> >>
> >> > m > 1 ## gave logical(0), now remains matrix identical to Lm
> >> (logical)
> >> > m > 0.1[0] ## ditto
> >> > m > NULL ## ditto
> >>
> >> > ## 3. 
> >> > mm < m[,c(1:2,2:1,2)]
> >> > try( m == mm ) ## now gives error "nonconformable arrays",
> >> > ## but gave logical(0) in R <= 3.3.x
> >>
> >> > ## 4. 
> >> > str( Im + NULL) ## gave "num", now gives "int"
> >>
> >> > ## 5. 
> >> > ## special case for arithmetic w/ length1 array
> >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
> >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
> >>
> >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
> >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match
> the
> >> length of object [2]
> >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
> >> > ##
> >> > ## non0length arrays combined with {NULL or double() or ...}
> *fail*
> >>
> >> > ### Length1 arrays: Arithmetic with vectors > 1 treated array
> >> as scalar
> >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
> >> warning to "be ERROR"
> >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an *error*
> >> now in R >= 3.4.0
> >> > tools::assertError(m1 & NULL) # gave and gives error
> >> > tools::assertError(m1  double())# ditto
> >> > ## m2 was slightly different:
> >> > tools::assertError(m2 + NULL)
> >> > tools::assertError(m2 & NULL)
> >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
> above!
> >>
> >> > 
> >> 
> >>
> >>
> >> > Note that in R's own 'nls' sources, there was one case of
> >> > situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
> >>
> >> > In such cases, you should explicitly coerce it to a vector,
> >> > either ("selfexplainingly") by as.vector(.), or as I did in
> >> > the nls case by c(.) : The latter is much less
> >> > selfexplaining, but nicer to read in mathematical formulae, and
> >> > currently also more efficient because it is a .Primitive.
> >>
> >> > Please use Rdevel with your code, and let us know if you see
> >> > effects that seem adverse.
> >>
> >> I've been slightly surprised (or even "frustrated") by the empty
> >> reaction on our Rdevel list to this post.
> >>
> >> I would have expected some critique, may be even some praise,
> >> ... in any case some sign people are "thinking along" (as we say
> >> in German).
> >>
> >> In the mean time, I've actually thought along the one case which
> >> is last above: The <op> (binary operation) between a
> >> non0length array and a 0length vector (and NULL which should
> >> be treated like a 0length vector):
> >>
> >> R <= 3.3.1 *is* quite inconsistent with these:
> >>
> >>
> >> and my proposal above (implemented in Rdevel, since Sep.5) would
> give an
> >> error for all these, but instead, R really could be more lenient
> here:
> >> A 0length result is ok, and it should *not* inherit the array
> >> (dim, dimnames), since the array is not of length 0. So instead
> >> of the above [for the very last part only!!], we would aim for
> >> the following. These *all* give an error in current Rdevel,
> >> with the exception of 'm1 + NULL' which "only" gives a "bad
> >> warning" :
> >>
> >> 
> >>
> >> m1 < matrix(1,1)
> >> m2 < matrix(1,2)
> >>
> >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
> >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
> >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
> ?!
> >> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0)
> ?!
> >> ## m2 slightly different:
> >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
> >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0) ?!
> >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
> >>
> >> 
> >>
> >> This would be slightly more backcompatible than the currently
> >> implemented proposal. Everything else I said remains true, and
> >> I'm pretty sure most changes needed in packages would remain to be
> done.
> >>
> >> Opinions ?
> >>
> >>
> >>
> >> > In some case where Rdevel now gives an error but did not
> >> > previously, we could contemplate giving another "warning
> >> > .... 'to become ERROR'" if there was too much breakage, though
> >> > I don't expect that.
> >>
> >>
> >> > For the R Core Team,
> >>
> >> > Martin Maechler,
> >> > ETH Zurich
> >>
> >> ______________________________________________
> >> [hidden email] mailing list
> >> https://stat.ethz.ch/mailman/listinfo/rdevel> >>
>
>
>
> > 
> > Robin Hankin
> > Neutral theorist
> > [hidden email]
>
> > [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel>

Gabriel Becker, PhD
Associate Scientist (Bioinformatics)
Genentech Research
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Shouldn't binary operators (arithmetic and logical) should throw an error
when one operand is NULL (or other type that doesn't make sense)? This is
a different case than a zerolength operand of a legitimate type. E.g.,
any(x < 0)
should return FALSE if x is numberlike and length(x)==0 but give an error
if x is NULL.
I.e., I think the type check should be done before the length check.
Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]> wrote:
> Martin,
>
> Like Robin and Oliver I think this type of edgecase consistency is
> important and that it's fantastic that Rcore  and you personally  are
> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
> this really does combine to go a long way to making R better and better.
>
> I do wonder a bit about the
>
> x = 1:2
>
> y = NULL
>
> x < y
>
> case.
>
> Returning a logical of length 0 is more backwards compatible, but is it
> ever what the author actually intended? I have trouble thinking of a case
> where that lessthan didn't carry an implicit assumption that y was
> nonNULL. I can say that in my own code, I've never hit that behavior in a
> case that wasn't an error.
>
> My vote (unless someone else points out a compelling use for the behavior)
> is for the to throw an error. As a developer, I'd rather things like this
> break so the bug in my logic is visible, rather than propagating as the
> 0length logical is &'ed or 'ed with other logical vectors, or used to
> subset, or (in the case it should be length 1) passed to if() (if throws an
> error now, but the rest would silently "work").
>
> Best,
> ~G
>
> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
> [hidden email]>
> wrote:
>
> > >>>>> robin hankin < [hidden email]>
> > >>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
> >
> > > Martin I'd like to make a comment; I think that R's
> > > behaviour on 'edge' cases like this is an important thing
> > > and it's great that you are working on it.
> >
> > > I make heavy use of zeroextent arrays, chiefly because
> > > the dimnames are an efficient and logical way to keep
> > > track of certain types of information.
> >
> > > If I have, for example,
> >
> > > a < array(0,c(2,0,2))
> > > dimnames(a) < list(name=c('Mike','Kevin'),
> > NULL,item=c("hat","scarf"))
> >
> >
> > > Then in R3.3.1, 70800 I get
> >
> > a> 0
> > > logical(0)
> > >>
> >
> > > But in 71219 I get
> >
> > a> 0
> > > , , item = hat
> >
> >
> > > name
> > > Mike
> > > Kevin
> >
> > > , , item = scarf
> >
> >
> > > name
> > > Mike
> > > Kevin
> >
> > > (which is an empty logical array that holds the names of the people
> > and
> > > their clothes). I find the behaviour of 71219 very much preferable
> > because
> > > there is no reason to discard the information in the dimnames.
> >
> > Thanks a lot, Robin, (and Oliver) !
> >
> > Yes, the above is such a case where the new behavior makes much sense.
> > And this behavior remains identical after the 71222 amendment.
> >
> > Martin
> >
> > > Best wishes
> > > Robin
> >
> >
> >
> >
> > > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
> > [hidden email]>
> > > wrote:
> >
> > >> >>>>> Martin Maechler < [hidden email]>
> > >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
> > >>
> > >> > Yesterday, changes to R's development version were committed,
> > >> relating
> > >> > to arithmetic, logic ('&' and '') and
> > >> > comparison/relational ('<', '==') binary operators
> > >> > which in NEWS are described as
> > >>
> > >> > SIGNIFICANT USERVISIBLE CHANGES:
> > >>
> > >> > [.............]
> > >>
> > >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
> > >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
> > >> > behave consistently, notably for arrays of length zero.
> > >>
> > >> > Arithmetic between length1 arrays and longer nonarrays had
> > >> > silently dropped the array attributes and recycled. This
> > >> > now gives a warning and will signal an error in the future,
> > >> > as it has always for logic and comparison operations in
> > >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
> > >> > ‘matrix(1,1) < 2:3’).
> > >>
> > >> > As the above "visually suggests" one could think of the changes
> > >> > falling mainly two groups,
> > >> > 1) <0extent array> (op) <nonarray>
> > >> > 2) <1extent array> (arith) <nonarray of length != 1>
> > >>
> > >> > These changes are partly nonback compatible and may break
> > >> > existing code. We believe that the internal consistency gained
> > >> > from the changes is worth the few places with problems.
> > >>
> > >> > We expect some package maintainers (1020, or even more?) need
> > >> > to adapt their code.
> > >>
> > >> > Case '2)' above mainly results in a new warning, e.g.,
> > >>
> > >> >> matrix(1,1) + 1:2
> > >> > [1] 2 3
> > >> > Warning message:
> > >> > In matrix(1, 1) + 1:2 :
> > >> > dropping dim() of array of length one. Will become ERROR
> > >> >>
> > >>
> > >> > whereas '1)' gives errors in cases the result silently was a
> > >> > vector of length zero, or also keeps array (dim & dimnames) in
> > >> > cases these were silently dropped.
> > >>
> > >> > The following is a "heavily" commented R script showing (all ?)
> > >> > the important cases with changes :
> > >>
> > >> > 
> > >> 
> > >>
> > >> > (m < cbind(a=1[0], b=2[0]))
> > >> > Lm < m; storage.mode(Lm) < "logical"
> > >> > Im < m; storage.mode(Im) < "integer"
> > >>
> > >> > ## 1. 
> > >> > try( m & NULL ) # in R <= 3.3.x :
> > >> > ## Error in m & NULL :
> > >> > ## operations are possible only for numeric, logical or complex
> > >> types
> > >> > ##
> > >> > ## gives 'Lm' in R >= 3.4.0
> > >>
> > >> > ## 2. 
> > >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
> > >> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
> > >> (integer)
> > >>
> > >> > m > 1 ## gave logical(0), now remains matrix identical to
> Lm
> > >> (logical)
> > >> > m > 0.1[0] ## ditto
> > >> > m > NULL ## ditto
> > >>
> > >> > ## 3. 
> > >> > mm < m[,c(1:2,2:1,2)]
> > >> > try( m == mm ) ## now gives error "nonconformable arrays",
> > >> > ## but gave logical(0) in R <= 3.3.x
> > >>
> > >> > ## 4. 
> > >> > str( Im + NULL) ## gave "num", now gives "int"
> > >>
> > >> > ## 5. 
> > >> > ## special case for arithmetic w/ length1 array
> > >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
> > >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
> > >>
> > >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
> > >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not match
> > the
> > >> length of object [2]
> > >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
> > >> > ##
> > >> > ## non0length arrays combined with {NULL or double() or ...}
> > *fail*
> > >>
> > >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
> array
> > >> as scalar
> > >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
> > >> warning to "be ERROR"
> > >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
> *error*
> > >> now in R >= 3.4.0
> > >> > tools::assertError(m1 & NULL) # gave and gives error
> > >> > tools::assertError(m1  double())# ditto
> > >> > ## m2 was slightly different:
> > >> > tools::assertError(m2 + NULL)
> > >> > tools::assertError(m2 & NULL)
> > >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
> > above!
> > >>
> > >> > 
> > >> 
> > >>
> > >>
> > >> > Note that in R's own 'nls' sources, there was one case of
> > >> > situation '2)' above, i.e. a 1x1matrix was used as a "scalar".
> > >>
> > >> > In such cases, you should explicitly coerce it to a vector,
> > >> > either ("selfexplainingly") by as.vector(.), or as I did in
> > >> > the nls case by c(.) : The latter is much less
> > >> > selfexplaining, but nicer to read in mathematical formulae, and
> > >> > currently also more efficient because it is a .Primitive.
> > >>
> > >> > Please use Rdevel with your code, and let us know if you see
> > >> > effects that seem adverse.
> > >>
> > >> I've been slightly surprised (or even "frustrated") by the empty
> > >> reaction on our Rdevel list to this post.
> > >>
> > >> I would have expected some critique, may be even some praise,
> > >> ... in any case some sign people are "thinking along" (as we say
> > >> in German).
> > >>
> > >> In the mean time, I've actually thought along the one case which
> > >> is last above: The <op> (binary operation) between a
> > >> non0length array and a 0length vector (and NULL which should
> > >> be treated like a 0length vector):
> > >>
> > >> R <= 3.3.1 *is* quite inconsistent with these:
> > >>
> > >>
> > >> and my proposal above (implemented in Rdevel, since Sep.5) would
> > give an
> > >> error for all these, but instead, R really could be more lenient
> > here:
> > >> A 0length result is ok, and it should *not* inherit the array
> > >> (dim, dimnames), since the array is not of length 0. So instead
> > >> of the above [for the very last part only!!], we would aim for
> > >> the following. These *all* give an error in current Rdevel,
> > >> with the exception of 'm1 + NULL' which "only" gives a "bad
> > >> warning" :
> > >>
> > >> 
> > >>
> > >> m1 < matrix(1,1)
> > >> m2 < matrix(1,2)
> > >>
> > >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
> > >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
> > >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
> > ?!
> > >> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0)
> > ?!
> > >> ## m2 slightly different:
> > >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0) ?!
> > >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
> ?!
> > >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
> > >>
> > >> 
> > >>
> > >> This would be slightly more backcompatible than the currently
> > >> implemented proposal. Everything else I said remains true, and
> > >> I'm pretty sure most changes needed in packages would remain to be
> > done.
> > >>
> > >> Opinions ?
> > >>
> > >>
> > >>
> > >> > In some case where Rdevel now gives an error but did not
> > >> > previously, we could contemplate giving another "warning
> > >> > .... 'to become ERROR'" if there was too much breakage, though
> > >> > I don't expect that.
> > >>
> > >>
> > >> > For the R Core Team,
> > >>
> > >> > Martin Maechler,
> > >> > ETH Zurich
> > >>
> > >> ______________________________________________
> > >> [hidden email] mailing list
> > >> https://stat.ethz.ch/mailman/listinfo/rdevel> > >>
> >
> >
> >
> > > 
> > > Robin Hankin
> > > Neutral theorist
> > > [hidden email]
> >
> > > [[alternative HTML version deleted]]
> >
> > ______________________________________________
> > [hidden email] mailing list
> > https://stat.ethz.ch/mailman/listinfo/rdevel> >
>
>
>
> 
> Gabriel Becker, PhD
> Associate Scientist (Bioinformatics)
> Genentech Research
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel>
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
> Shouldn't binary operators (arithmetic and logical) should throw an error
> when one operand is NULL (or other type that doesn't make sense)? This is
> a different case than a zerolength operand of a legitimate type. E.g.,
> any(x < 0)
> should return FALSE if x is numberlike and length(x)==0 but give an error
> if x is NULL.
>
Bill,
That is a good point. I can see the argument for this in the case that the
nonzero length is 1. I'm not sure which is better though. If we switch
any() to all(), things get murky.
Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
all(x>0)), but the likelihood of this being a thoughtbug on the author's
part is exceedingly high, imho. So the desirable behavior seems to depend
on the angle we look at it from.
My personal opinion is that x < y with length(x)==0 should fail if length(y)
> 1, at least, and I'd be for it being an error even if y is length 1,
though I do acknowledge this is more likely (though still quite unlikely
imho) to be the intended behavior.
~G
>
> I.e., I think the type check should be done before the length check.
>
>
> Bill Dunlap
> TIBCO Software
> wdunlap tibco.com
>
> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
> wrote:
>
>> Martin,
>>
>> Like Robin and Oliver I think this type of edgecase consistency is
>> important and that it's fantastic that Rcore  and you personally  are
>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>> this really does combine to go a long way to making R better and better.
>>
>> I do wonder a bit about the
>>
>> x = 1:2
>>
>> y = NULL
>>
>> x < y
>>
>> case.
>>
>> Returning a logical of length 0 is more backwards compatible, but is it
>> ever what the author actually intended? I have trouble thinking of a case
>> where that lessthan didn't carry an implicit assumption that y was
>> nonNULL. I can say that in my own code, I've never hit that behavior in
>> a
>> case that wasn't an error.
>>
>> My vote (unless someone else points out a compelling use for the behavior)
>> is for the to throw an error. As a developer, I'd rather things like this
>> break so the bug in my logic is visible, rather than propagating as the
>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>> subset, or (in the case it should be length 1) passed to if() (if throws
>> an
>> error now, but the rest would silently "work").
>>
>> Best,
>> ~G
>>
>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>> [hidden email]>
>> wrote:
>>
>> > >>>>> robin hankin < [hidden email]>
>> > >>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>> >
>> > > Martin I'd like to make a comment; I think that R's
>> > > behaviour on 'edge' cases like this is an important thing
>> > > and it's great that you are working on it.
>> >
>> > > I make heavy use of zeroextent arrays, chiefly because
>> > > the dimnames are an efficient and logical way to keep
>> > > track of certain types of information.
>> >
>> > > If I have, for example,
>> >
>> > > a < array(0,c(2,0,2))
>> > > dimnames(a) < list(name=c('Mike','Kevin'),
>> > NULL,item=c("hat","scarf"))
>> >
>> >
>> > > Then in R3.3.1, 70800 I get
>> >
>> > a> 0
>> > > logical(0)
>> > >>
>> >
>> > > But in 71219 I get
>> >
>> > a> 0
>> > > , , item = hat
>> >
>> >
>> > > name
>> > > Mike
>> > > Kevin
>> >
>> > > , , item = scarf
>> >
>> >
>> > > name
>> > > Mike
>> > > Kevin
>> >
>> > > (which is an empty logical array that holds the names of the
>> people
>> > and
>> > > their clothes). I find the behaviour of 71219 very much preferable
>> > because
>> > > there is no reason to discard the information in the dimnames.
>> >
>> > Thanks a lot, Robin, (and Oliver) !
>> >
>> > Yes, the above is such a case where the new behavior makes much sense.
>> > And this behavior remains identical after the 71222 amendment.
>> >
>> > Martin
>> >
>> > > Best wishes
>> > > Robin
>> >
>> >
>> >
>> >
>> > > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>> > [hidden email]>
>> > > wrote:
>> >
>> > >> >>>>> Martin Maechler < [hidden email]>
>> > >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>> > >>
>> > >> > Yesterday, changes to R's development version were committed,
>> > >> relating
>> > >> > to arithmetic, logic ('&' and '') and
>> > >> > comparison/relational ('<', '==') binary operators
>> > >> > which in NEWS are described as
>> > >>
>> > >> > SIGNIFICANT USERVISIBLE CHANGES:
>> > >>
>> > >> > [.............]
>> > >>
>> > >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>> > >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>> > >> > behave consistently, notably for arrays of length zero.
>> > >>
>> > >> > Arithmetic between length1 arrays and longer nonarrays had
>> > >> > silently dropped the array attributes and recycled. This
>> > >> > now gives a warning and will signal an error in the future,
>> > >> > as it has always for logic and comparison operations in
>> > >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>> > >> > ‘matrix(1,1) < 2:3’).
>> > >>
>> > >> > As the above "visually suggests" one could think of the changes
>> > >> > falling mainly two groups,
>> > >> > 1) <0extent array> (op) <nonarray>
>> > >> > 2) <1extent array> (arith) <nonarray of length != 1>
>> > >>
>> > >> > These changes are partly nonback compatible and may break
>> > >> > existing code. We believe that the internal consistency gained
>> > >> > from the changes is worth the few places with problems.
>> > >>
>> > >> > We expect some package maintainers (1020, or even more?) need
>> > >> > to adapt their code.
>> > >>
>> > >> > Case '2)' above mainly results in a new warning, e.g.,
>> > >>
>> > >> >> matrix(1,1) + 1:2
>> > >> > [1] 2 3
>> > >> > Warning message:
>> > >> > In matrix(1, 1) + 1:2 :
>> > >> > dropping dim() of array of length one. Will become ERROR
>> > >> >>
>> > >>
>> > >> > whereas '1)' gives errors in cases the result silently was a
>> > >> > vector of length zero, or also keeps array (dim & dimnames) in
>> > >> > cases these were silently dropped.
>> > >>
>> > >> > The following is a "heavily" commented R script showing (all
>> ?)
>> > >> > the important cases with changes :
>> > >>
>> > >> > 
>> > >> 
>> > >>
>> > >> > (m < cbind(a=1[0], b=2[0]))
>> > >> > Lm < m; storage.mode(Lm) < "logical"
>> > >> > Im < m; storage.mode(Im) < "integer"
>> > >>
>> > >> > ## 1. 
>> > >> > try( m & NULL ) # in R <= 3.3.x :
>> > >> > ## Error in m & NULL :
>> > >> > ## operations are possible only for numeric, logical or
>> complex
>> > >> types
>> > >> > ##
>> > >> > ## gives 'Lm' in R >= 3.4.0
>> > >>
>> > >> > ## 2. 
>> > >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>> > >> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
>> > >> (integer)
>> > >>
>> > >> > m > 1 ## gave logical(0), now remains matrix identical to
>> Lm
>> > >> (logical)
>> > >> > m > 0.1[0] ## ditto
>> > >> > m > NULL ## ditto
>> > >>
>> > >> > ## 3. 
>> > >> > mm < m[,c(1:2,2:1,2)]
>> > >> > try( m == mm ) ## now gives error "nonconformable arrays",
>> > >> > ## but gave logical(0) in R <= 3.3.x
>> > >>
>> > >> > ## 4. 
>> > >> > str( Im + NULL) ## gave "num", now gives "int"
>> > >>
>> > >> > ## 5. 
>> > >> > ## special case for arithmetic w/ length1 array
>> > >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>> > >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>> > >>
>> > >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>> > >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>> match
>> > the
>> > >> length of object [2]
>> > >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>> > >> > ##
>> > >> > ## non0length arrays combined with {NULL or double() or ...}
>> > *fail*
>> > >>
>> > >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>> array
>> > >> as scalar
>> > >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>> > >> warning to "be ERROR"
>> > >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>> *error*
>> > >> now in R >= 3.4.0
>> > >> > tools::assertError(m1 & NULL) # gave and gives error
>> > >> > tools::assertError(m1  double())# ditto
>> > >> > ## m2 was slightly different:
>> > >> > tools::assertError(m2 + NULL)
>> > >> > tools::assertError(m2 & NULL)
>> > >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>> > above!
>> > >>
>> > >> > 
>> > >> 
>> > >>
>> > >>
>> > >> > Note that in R's own 'nls' sources, there was one case of
>> > >> > situation '2)' above, i.e. a 1x1matrix was used as a
>> "scalar".
>> > >>
>> > >> > In such cases, you should explicitly coerce it to a vector,
>> > >> > either ("selfexplainingly") by as.vector(.), or as I did in
>> > >> > the nls case by c(.) : The latter is much less
>> > >> > selfexplaining, but nicer to read in mathematical formulae,
>> and
>> > >> > currently also more efficient because it is a .Primitive.
>> > >>
>> > >> > Please use Rdevel with your code, and let us know if you see
>> > >> > effects that seem adverse.
>> > >>
>> > >> I've been slightly surprised (or even "frustrated") by the empty
>> > >> reaction on our Rdevel list to this post.
>> > >>
>> > >> I would have expected some critique, may be even some praise,
>> > >> ... in any case some sign people are "thinking along" (as we say
>> > >> in German).
>> > >>
>> > >> In the mean time, I've actually thought along the one case which
>> > >> is last above: The <op> (binary operation) between a
>> > >> non0length array and a 0length vector (and NULL which should
>> > >> be treated like a 0length vector):
>> > >>
>> > >> R <= 3.3.1 *is* quite inconsistent with these:
>> > >>
>> > >>
>> > >> and my proposal above (implemented in Rdevel, since Sep.5) would
>> > give an
>> > >> error for all these, but instead, R really could be more lenient
>> > here:
>> > >> A 0length result is ok, and it should *not* inherit the array
>> > >> (dim, dimnames), since the array is not of length 0. So instead
>> > >> of the above [for the very last part only!!], we would aim for
>> > >> the following. These *all* give an error in current Rdevel,
>> > >> with the exception of 'm1 + NULL' which "only" gives a "bad
>> > >> warning" :
>> > >>
>> > >> 
>> > >>
>> > >> m1 < matrix(1,1)
>> > >> m2 < matrix(1,2)
>> > >>
>> > >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>> > >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>> > >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>> > ?!
>> > >> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0)
>> > ?!
>> > >> ## m2 slightly different:
>> > >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>> ?!
>> > >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>> ?!
>> > >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>> > >>
>> > >> 
>> > >>
>> > >> This would be slightly more backcompatible than the currently
>> > >> implemented proposal. Everything else I said remains true, and
>> > >> I'm pretty sure most changes needed in packages would remain to
>> be
>> > done.
>> > >>
>> > >> Opinions ?
>> > >>
>> > >>
>> > >>
>> > >> > In some case where Rdevel now gives an error but did not
>> > >> > previously, we could contemplate giving another "warning
>> > >> > .... 'to become ERROR'" if there was too much breakage, though
>> > >> > I don't expect that.
>> > >>
>> > >>
>> > >> > For the R Core Team,
>> > >>
>> > >> > Martin Maechler,
>> > >> > ETH Zurich
>> > >>
>> > >> ______________________________________________
>> > >> [hidden email] mailing list
>> > >> https://stat.ethz.ch/mailman/listinfo/rdevel>> > >>
>> >
>> >
>> >
>> > > 
>> > > Robin Hankin
>> > > Neutral theorist
>> > > [hidden email]
>> >
>> > > [[alternative HTML version deleted]]
>> >
>> > ______________________________________________
>> > [hidden email] mailing list
>> > https://stat.ethz.ch/mailman/listinfo/rdevel>> >
>>
>>
>>
>> 
>> Gabriel Becker, PhD
>> Associate Scientist (Bioinformatics)
>> Genentech Research
>>
>> [[alternative HTML version deleted]]
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel>>
>
>

Gabriel Becker, PhD
Associate Scientist (Bioinformatics)
Genentech Research
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Prior to the mid1990s, S did "length0 OP lengthn > rep(NA, n)" and it
was changed
to "length0 OP lengthn > length0" to avoid lots of problems like
any(x<0) being NA
when length(x)==0. Yes, people could code defensively by putting lots of
if(length(x)==0)...
in their code, but that is tedious and errorprone and creates really ugly
code.
Is your suggestion to leave the length0 OP length1 case as it is but make
length0 OP lengthtwoorhigher an error or warning (akin to the length2
OP length3 case)?
By the way, the all(numeric(0)<0) is TRUE, as is all(numeric()>0), by de
Morgan's rule, but that is not really relevant here.
Bill Dunlap
TIBCO Software
wdunlap tibco.com
On Thu, Sep 8, 2016 at 10:22 AM, Gabriel Becker < [hidden email]>
wrote:
>
>
> On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
>
>> Shouldn't binary operators (arithmetic and logical) should throw an error
>> when one operand is NULL (or other type that doesn't make sense)? This is
>> a different case than a zerolength operand of a legitimate type. E.g.,
>> any(x < 0)
>> should return FALSE if x is numberlike and length(x)==0 but give an
>> error if x is NULL.
>>
> Bill,
>
> That is a good point. I can see the argument for this in the case that the
> nonzero length is 1. I'm not sure which is better though. If we switch
> any() to all(), things get murky.
>
> Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
> all(x>0)), but the likelihood of this being a thoughtbug on the author's
> part is exceedingly high, imho. So the desirable behavior seems to depend
> on the angle we look at it from.
>
> My personal opinion is that x < y with length(x)==0 should fail if length(y)
> > 1, at least, and I'd be for it being an error even if y is length 1,
> though I do acknowledge this is more likely (though still quite unlikely
> imho) to be the intended behavior.
>
> ~G
>
>>
>> I.e., I think the type check should be done before the length check.
>>
>>
>> Bill Dunlap
>> TIBCO Software
>> wdunlap tibco.com
>>
>> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
>> wrote:
>>
>>> Martin,
>>>
>>> Like Robin and Oliver I think this type of edgecase consistency is
>>> important and that it's fantastic that Rcore  and you personally  are
>>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>>> this really does combine to go a long way to making R better and better.
>>>
>>> I do wonder a bit about the
>>>
>>> x = 1:2
>>>
>>> y = NULL
>>>
>>> x < y
>>>
>>> case.
>>>
>>> Returning a logical of length 0 is more backwards compatible, but is it
>>> ever what the author actually intended? I have trouble thinking of a case
>>> where that lessthan didn't carry an implicit assumption that y was
>>> nonNULL. I can say that in my own code, I've never hit that behavior
>>> in a
>>> case that wasn't an error.
>>>
>>> My vote (unless someone else points out a compelling use for the
>>> behavior)
>>> is for the to throw an error. As a developer, I'd rather things like this
>>> break so the bug in my logic is visible, rather than propagating as the
>>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>>> subset, or (in the case it should be length 1) passed to if() (if throws
>>> an
>>> error now, but the rest would silently "work").
>>>
>>> Best,
>>> ~G
>>>
>>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>>> [hidden email]>
>>> wrote:
>>>
>>> > >>>>> robin hankin < [hidden email]>
>>> > >>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>>> >
>>> > > Martin I'd like to make a comment; I think that R's
>>> > > behaviour on 'edge' cases like this is an important thing
>>> > > and it's great that you are working on it.
>>> >
>>> > > I make heavy use of zeroextent arrays, chiefly because
>>> > > the dimnames are an efficient and logical way to keep
>>> > > track of certain types of information.
>>> >
>>> > > If I have, for example,
>>> >
>>> > > a < array(0,c(2,0,2))
>>> > > dimnames(a) < list(name=c('Mike','Kevin'),
>>> > NULL,item=c("hat","scarf"))
>>> >
>>> >
>>> > > Then in R3.3.1, 70800 I get
>>> >
>>> > a> 0
>>> > > logical(0)
>>> > >>
>>> >
>>> > > But in 71219 I get
>>> >
>>> > a> 0
>>> > > , , item = hat
>>> >
>>> >
>>> > > name
>>> > > Mike
>>> > > Kevin
>>> >
>>> > > , , item = scarf
>>> >
>>> >
>>> > > name
>>> > > Mike
>>> > > Kevin
>>> >
>>> > > (which is an empty logical array that holds the names of the
>>> people
>>> > and
>>> > > their clothes). I find the behaviour of 71219 very much
>>> preferable
>>> > because
>>> > > there is no reason to discard the information in the dimnames.
>>> >
>>> > Thanks a lot, Robin, (and Oliver) !
>>> >
>>> > Yes, the above is such a case where the new behavior makes much sense.
>>> > And this behavior remains identical after the 71222 amendment.
>>> >
>>> > Martin
>>> >
>>> > > Best wishes
>>> > > Robin
>>> >
>>> >
>>> >
>>> >
>>> > > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>>> > [hidden email]>
>>> > > wrote:
>>> >
>>> > >> >>>>> Martin Maechler < [hidden email]>
>>> > >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>> > >>
>>> > >> > Yesterday, changes to R's development version were committed,
>>> > >> relating
>>> > >> > to arithmetic, logic ('&' and '') and
>>> > >> > comparison/relational ('<', '==') binary operators
>>> > >> > which in NEWS are described as
>>> > >>
>>> > >> > SIGNIFICANT USERVISIBLE CHANGES:
>>> > >>
>>> > >> > [.............]
>>> > >>
>>> > >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>>> > >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>>> > >> > behave consistently, notably for arrays of length zero.
>>> > >>
>>> > >> > Arithmetic between length1 arrays and longer nonarrays had
>>> > >> > silently dropped the array attributes and recycled. This
>>> > >> > now gives a warning and will signal an error in the future,
>>> > >> > as it has always for logic and comparison operations in
>>> > >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>>> > >> > ‘matrix(1,1) < 2:3’).
>>> > >>
>>> > >> > As the above "visually suggests" one could think of the
>>> changes
>>> > >> > falling mainly two groups,
>>> > >> > 1) <0extent array> (op) <nonarray>
>>> > >> > 2) <1extent array> (arith) <nonarray of length != 1>
>>> > >>
>>> > >> > These changes are partly nonback compatible and may break
>>> > >> > existing code. We believe that the internal consistency
>>> gained
>>> > >> > from the changes is worth the few places with problems.
>>> > >>
>>> > >> > We expect some package maintainers (1020, or even more?) need
>>> > >> > to adapt their code.
>>> > >>
>>> > >> > Case '2)' above mainly results in a new warning, e.g.,
>>> > >>
>>> > >> >> matrix(1,1) + 1:2
>>> > >> > [1] 2 3
>>> > >> > Warning message:
>>> > >> > In matrix(1, 1) + 1:2 :
>>> > >> > dropping dim() of array of length one. Will become ERROR
>>> > >> >>
>>> > >>
>>> > >> > whereas '1)' gives errors in cases the result silently was a
>>> > >> > vector of length zero, or also keeps array (dim & dimnames) in
>>> > >> > cases these were silently dropped.
>>> > >>
>>> > >> > The following is a "heavily" commented R script showing (all
>>> ?)
>>> > >> > the important cases with changes :
>>> > >>
>>> > >> > 
>>> > >> 
>>> > >>
>>> > >> > (m < cbind(a=1[0], b=2[0]))
>>> > >> > Lm < m; storage.mode(Lm) < "logical"
>>> > >> > Im < m; storage.mode(Im) < "integer"
>>> > >>
>>> > >> > ## 1. 
>>> > >> > try( m & NULL ) # in R <= 3.3.x :
>>> > >> > ## Error in m & NULL :
>>> > >> > ## operations are possible only for numeric, logical or
>>> complex
>>> > >> types
>>> > >> > ##
>>> > >> > ## gives 'Lm' in R >= 3.4.0
>>> > >>
>>> > >> > ## 2. 
>>> > >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>>> > >> > Im + 2:3 ## gave integer(0), now remains matrix identical to
>>> Im
>>> > >> (integer)
>>> > >>
>>> > >> > m > 1 ## gave logical(0), now remains matrix identical
>>> to Lm
>>> > >> (logical)
>>> > >> > m > 0.1[0] ## ditto
>>> > >> > m > NULL ## ditto
>>> > >>
>>> > >> > ## 3. 
>>> > >> > mm < m[,c(1:2,2:1,2)]
>>> > >> > try( m == mm ) ## now gives error "nonconformable arrays",
>>> > >> > ## but gave logical(0) in R <= 3.3.x
>>> > >>
>>> > >> > ## 4. 
>>> > >> > str( Im + NULL) ## gave "num", now gives "int"
>>> > >>
>>> > >> > ## 5. 
>>> > >> > ## special case for arithmetic w/ length1 array
>>> > >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>>> > >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>> > >>
>>> > >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>>> > >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>>> match
>>> > the
>>> > >> length of object [2]
>>> > >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>>> > >> > ##
>>> > >> > ## non0length arrays combined with {NULL or double() or ...}
>>> > *fail*
>>> > >>
>>> > >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>>> array
>>> > >> as scalar
>>> > >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>>> > >> warning to "be ERROR"
>>> > >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>>> *error*
>>> > >> now in R >= 3.4.0
>>> > >> > tools::assertError(m1 & NULL) # gave and gives error
>>> > >> > tools::assertError(m1  double())# ditto
>>> > >> > ## m2 was slightly different:
>>> > >> > tools::assertError(m2 + NULL)
>>> > >> > tools::assertError(m2 & NULL)
>>> > >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>>> > above!
>>> > >>
>>> > >> > 
>>> > >> 
>>> > >>
>>> > >>
>>> > >> > Note that in R's own 'nls' sources, there was one case of
>>> > >> > situation '2)' above, i.e. a 1x1matrix was used as a
>>> "scalar".
>>> > >>
>>> > >> > In such cases, you should explicitly coerce it to a vector,
>>> > >> > either ("selfexplainingly") by as.vector(.), or as I did in
>>> > >> > the nls case by c(.) : The latter is much less
>>> > >> > selfexplaining, but nicer to read in mathematical formulae,
>>> and
>>> > >> > currently also more efficient because it is a .Primitive.
>>> > >>
>>> > >> > Please use Rdevel with your code, and let us know if you see
>>> > >> > effects that seem adverse.
>>> > >>
>>> > >> I've been slightly surprised (or even "frustrated") by the empty
>>> > >> reaction on our Rdevel list to this post.
>>> > >>
>>> > >> I would have expected some critique, may be even some praise,
>>> > >> ... in any case some sign people are "thinking along" (as we say
>>> > >> in German).
>>> > >>
>>> > >> In the mean time, I've actually thought along the one case which
>>> > >> is last above: The <op> (binary operation) between a
>>> > >> non0length array and a 0length vector (and NULL which should
>>> > >> be treated like a 0length vector):
>>> > >>
>>> > >> R <= 3.3.1 *is* quite inconsistent with these:
>>> > >>
>>> > >>
>>> > >> and my proposal above (implemented in Rdevel, since Sep.5)
>>> would
>>> > give an
>>> > >> error for all these, but instead, R really could be more lenient
>>> > here:
>>> > >> A 0length result is ok, and it should *not* inherit the array
>>> > >> (dim, dimnames), since the array is not of length 0. So instead
>>> > >> of the above [for the very last part only!!], we would aim for
>>> > >> the following. These *all* give an error in current Rdevel,
>>> > >> with the exception of 'm1 + NULL' which "only" gives a "bad
>>> > >> warning" :
>>> > >>
>>> > >> 
>>> > >>
>>> > >> m1 < matrix(1,1)
>>> > >> m2 < matrix(1,2)
>>> > >>
>>> > >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>>> > >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>>> > >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to
>>> logical(0)
>>> > ?!
>>> > >> try(m1  double())# ERROR in R <= 3.3.x > change to
>>> logical(0)
>>> > ?!
>>> > >> ## m2 slightly different:
>>> > >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>>> ?!
>>> > >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to
>>> logical(0) ?!
>>> > >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>> > >>
>>> > >> 
>>> > >>
>>> > >> This would be slightly more backcompatible than the currently
>>> > >> implemented proposal. Everything else I said remains true, and
>>> > >> I'm pretty sure most changes needed in packages would remain to
>>> be
>>> > done.
>>> > >>
>>> > >> Opinions ?
>>> > >>
>>> > >>
>>> > >>
>>> > >> > In some case where Rdevel now gives an error but did not
>>> > >> > previously, we could contemplate giving another "warning
>>> > >> > .... 'to become ERROR'" if there was too much breakage,
>>> though
>>> > >> > I don't expect that.
>>> > >>
>>> > >>
>>> > >> > For the R Core Team,
>>> > >>
>>> > >> > Martin Maechler,
>>> > >> > ETH Zurich
>>> > >>
>>> > >> ______________________________________________
>>> > >> [hidden email] mailing list
>>> > >> https://stat.ethz.ch/mailman/listinfo/rdevel>>> > >>
>>> >
>>> >
>>> >
>>> > > 
>>> > > Robin Hankin
>>> > > Neutral theorist
>>> > > [hidden email]
>>> >
>>> > > [[alternative HTML version deleted]]
>>> >
>>> > ______________________________________________
>>> > [hidden email] mailing list
>>> > https://stat.ethz.ch/mailman/listinfo/rdevel>>> >
>>>
>>>
>>>
>>> 
>>> Gabriel Becker, PhD
>>> Associate Scientist (Bioinformatics)
>>> Genentech Research
>>>
>>> [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>
>>
>>
>
>
> 
> Gabriel Becker, PhD
> Associate Scientist (Bioinformatics)
> Genentech Research
>
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


On 09/08/2016 01:22 PM, Gabriel Becker wrote:
> On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
>
>> Shouldn't binary operators (arithmetic and logical) should throw an error
>> when one operand is NULL (or other type that doesn't make sense)? This is
>> a different case than a zerolength operand of a legitimate type. E.g.,
>> any(x < 0)
>> should return FALSE if x is numberlike and length(x)==0 but give an error
>> if x is NULL.
>>
> Bill,
>
> That is a good point. I can see the argument for this in the case that the
> nonzero length is 1. I'm not sure which is better though. If we switch
> any() to all(), things get murky.
>
> Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
> all(x>0)), but the likelihood of this being a thoughtbug on the author's
> part is exceedingly high, imho.
I suspect there may be more R users than you think that understand and
use vacuously true in code. I don't really like the idea of turning a
perfectly good and properly documented mathematical test into an error
in order to protect against a possible "thoughtbug".
Paul
So the desirable behavior seems to depend
> on the angle we look at it from.
>
> My personal opinion is that x < y with length(x)==0 should fail if length(y)
>> 1, at least, and I'd be for it being an error even if y is length 1,
> though I do acknowledge this is more likely (though still quite unlikely
> imho) to be the intended behavior.
>
> ~G
>
>>
>> I.e., I think the type check should be done before the length check.
>>
>>
>> Bill Dunlap
>> TIBCO Software
>> wdunlap tibco.com
>>
>> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
>> wrote:
>>
>>> Martin,
>>>
>>> Like Robin and Oliver I think this type of edgecase consistency is
>>> important and that it's fantastic that Rcore  and you personally  are
>>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>>> this really does combine to go a long way to making R better and better.
>>>
>>> I do wonder a bit about the
>>>
>>> x = 1:2
>>>
>>> y = NULL
>>>
>>> x < y
>>>
>>> case.
>>>
>>> Returning a logical of length 0 is more backwards compatible, but is it
>>> ever what the author actually intended? I have trouble thinking of a case
>>> where that lessthan didn't carry an implicit assumption that y was
>>> nonNULL. I can say that in my own code, I've never hit that behavior in
>>> a
>>> case that wasn't an error.
>>>
>>> My vote (unless someone else points out a compelling use for the behavior)
>>> is for the to throw an error. As a developer, I'd rather things like this
>>> break so the bug in my logic is visible, rather than propagating as the
>>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>>> subset, or (in the case it should be length 1) passed to if() (if throws
>>> an
>>> error now, but the rest would silently "work").
>>>
>>> Best,
>>> ~G
>>>
>>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>>> [hidden email]>
>>> wrote:
>>>
>>>>>>>>> robin hankin < [hidden email]>
>>>>>>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>>>>
>>>> > Martin I'd like to make a comment; I think that R's
>>>> > behaviour on 'edge' cases like this is an important thing
>>>> > and it's great that you are working on it.
>>>>
>>>> > I make heavy use of zeroextent arrays, chiefly because
>>>> > the dimnames are an efficient and logical way to keep
>>>> > track of certain types of information.
>>>>
>>>> > If I have, for example,
>>>>
>>>> > a < array(0,c(2,0,2))
>>>> > dimnames(a) < list(name=c('Mike','Kevin'),
>>>> NULL,item=c("hat","scarf"))
>>>>
>>>>
>>>> > Then in R3.3.1, 70800 I get
>>>>
>>>> a> 0
>>>> > logical(0)
>>>> >>
>>>>
>>>> > But in 71219 I get
>>>>
>>>> a> 0
>>>> > , , item = hat
>>>>
>>>>
>>>> > name
>>>> > Mike
>>>> > Kevin
>>>>
>>>> > , , item = scarf
>>>>
>>>>
>>>> > name
>>>> > Mike
>>>> > Kevin
>>>>
>>>> > (which is an empty logical array that holds the names of the
>>> people
>>>> and
>>>> > their clothes). I find the behaviour of 71219 very much preferable
>>>> because
>>>> > there is no reason to discard the information in the dimnames.
>>>>
>>>> Thanks a lot, Robin, (and Oliver) !
>>>>
>>>> Yes, the above is such a case where the new behavior makes much sense.
>>>> And this behavior remains identical after the 71222 amendment.
>>>>
>>>> Martin
>>>>
>>>> > Best wishes
>>>> > Robin
>>>>
>>>>
>>>>
>>>>
>>>> > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>>>> [hidden email]>
>>>> > wrote:
>>>>
>>>> >> >>>>> Martin Maechler < [hidden email]>
>>>> >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>>> >>
>>>> >> > Yesterday, changes to R's development version were committed,
>>>> >> relating
>>>> >> > to arithmetic, logic ('&' and '') and
>>>> >> > comparison/relational ('<', '==') binary operators
>>>> >> > which in NEWS are described as
>>>> >>
>>>> >> > SIGNIFICANT USERVISIBLE CHANGES:
>>>> >>
>>>> >> > [.............]
>>>> >>
>>>> >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>>>> >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>>>> >> > behave consistently, notably for arrays of length zero.
>>>> >>
>>>> >> > Arithmetic between length1 arrays and longer nonarrays had
>>>> >> > silently dropped the array attributes and recycled. This
>>>> >> > now gives a warning and will signal an error in the future,
>>>> >> > as it has always for logic and comparison operations in
>>>> >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>>>> >> > ‘matrix(1,1) < 2:3’).
>>>> >>
>>>> >> > As the above "visually suggests" one could think of the changes
>>>> >> > falling mainly two groups,
>>>> >> > 1) <0extent array> (op) <nonarray>
>>>> >> > 2) <1extent array> (arith) <nonarray of length != 1>
>>>> >>
>>>> >> > These changes are partly nonback compatible and may break
>>>> >> > existing code. We believe that the internal consistency gained
>>>> >> > from the changes is worth the few places with problems.
>>>> >>
>>>> >> > We expect some package maintainers (1020, or even more?) need
>>>> >> > to adapt their code.
>>>> >>
>>>> >> > Case '2)' above mainly results in a new warning, e.g.,
>>>> >>
>>>> >> >> matrix(1,1) + 1:2
>>>> >> > [1] 2 3
>>>> >> > Warning message:
>>>> >> > In matrix(1, 1) + 1:2 :
>>>> >> > dropping dim() of array of length one. Will become ERROR
>>>> >> >>
>>>> >>
>>>> >> > whereas '1)' gives errors in cases the result silently was a
>>>> >> > vector of length zero, or also keeps array (dim & dimnames) in
>>>> >> > cases these were silently dropped.
>>>> >>
>>>> >> > The following is a "heavily" commented R script showing (all
>>> ?)
>>>> >> > the important cases with changes :
>>>> >>
>>>> >> > 
>>>> >> 
>>>> >>
>>>> >> > (m < cbind(a=1[0], b=2[0]))
>>>> >> > Lm < m; storage.mode(Lm) < "logical"
>>>> >> > Im < m; storage.mode(Im) < "integer"
>>>> >>
>>>> >> > ## 1. 
>>>> >> > try( m & NULL ) # in R <= 3.3.x :
>>>> >> > ## Error in m & NULL :
>>>> >> > ## operations are possible only for numeric, logical or
>>> complex
>>>> >> types
>>>> >> > ##
>>>> >> > ## gives 'Lm' in R >= 3.4.0
>>>> >>
>>>> >> > ## 2. 
>>>> >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>>>> >> > Im + 2:3 ## gave integer(0), now remains matrix identical to Im
>>>> >> (integer)
>>>> >>
>>>> >> > m > 1 ## gave logical(0), now remains matrix identical to
>>> Lm
>>>> >> (logical)
>>>> >> > m > 0.1[0] ## ditto
>>>> >> > m > NULL ## ditto
>>>> >>
>>>> >> > ## 3. 
>>>> >> > mm < m[,c(1:2,2:1,2)]
>>>> >> > try( m == mm ) ## now gives error "nonconformable arrays",
>>>> >> > ## but gave logical(0) in R <= 3.3.x
>>>> >>
>>>> >> > ## 4. 
>>>> >> > str( Im + NULL) ## gave "num", now gives "int"
>>>> >>
>>>> >> > ## 5. 
>>>> >> > ## special case for arithmetic w/ length1 array
>>>> >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>>>> >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>>> >>
>>>> >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>>>> >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>>> match
>>>> the
>>>> >> length of object [2]
>>>> >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>>>> >> > ##
>>>> >> > ## non0length arrays combined with {NULL or double() or ...}
>>>> *fail*
>>>> >>
>>>> >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>>> array
>>>> >> as scalar
>>>> >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>>>> >> warning to "be ERROR"
>>>> >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>>> *error*
>>>> >> now in R >= 3.4.0
>>>> >> > tools::assertError(m1 & NULL) # gave and gives error
>>>> >> > tools::assertError(m1  double())# ditto
>>>> >> > ## m2 was slightly different:
>>>> >> > tools::assertError(m2 + NULL)
>>>> >> > tools::assertError(m2 & NULL)
>>>> >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>>>> above!
>>>> >>
>>>> >> > 
>>>> >> 
>>>> >>
>>>> >>
>>>> >> > Note that in R's own 'nls' sources, there was one case of
>>>> >> > situation '2)' above, i.e. a 1x1matrix was used as a
>>> "scalar".
>>>> >>
>>>> >> > In such cases, you should explicitly coerce it to a vector,
>>>> >> > either ("selfexplainingly") by as.vector(.), or as I did in
>>>> >> > the nls case by c(.) : The latter is much less
>>>> >> > selfexplaining, but nicer to read in mathematical formulae,
>>> and
>>>> >> > currently also more efficient because it is a .Primitive.
>>>> >>
>>>> >> > Please use Rdevel with your code, and let us know if you see
>>>> >> > effects that seem adverse.
>>>> >>
>>>> >> I've been slightly surprised (or even "frustrated") by the empty
>>>> >> reaction on our Rdevel list to this post.
>>>> >>
>>>> >> I would have expected some critique, may be even some praise,
>>>> >> ... in any case some sign people are "thinking along" (as we say
>>>> >> in German).
>>>> >>
>>>> >> In the mean time, I've actually thought along the one case which
>>>> >> is last above: The <op> (binary operation) between a
>>>> >> non0length array and a 0length vector (and NULL which should
>>>> >> be treated like a 0length vector):
>>>> >>
>>>> >> R <= 3.3.1 *is* quite inconsistent with these:
>>>> >>
>>>> >>
>>>> >> and my proposal above (implemented in Rdevel, since Sep.5) would
>>>> give an
>>>> >> error for all these, but instead, R really could be more lenient
>>>> here:
>>>> >> A 0length result is ok, and it should *not* inherit the array
>>>> >> (dim, dimnames), since the array is not of length 0. So instead
>>>> >> of the above [for the very last part only!!], we would aim for
>>>> >> the following. These *all* give an error in current Rdevel,
>>>> >> with the exception of 'm1 + NULL' which "only" gives a "bad
>>>> >> warning" :
>>>> >>
>>>> >> 
>>>> >>
>>>> >> m1 < matrix(1,1)
>>>> >> m2 < matrix(1,2)
>>>> >>
>>>> >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>>>> >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>>>> >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>>>> ?!
>>>> >> try(m1  double())# ERROR in R <= 3.3.x > change to logical(0)
>>>> ?!
>>>> >> ## m2 slightly different:
>>>> >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>>> ?!
>>>> >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>>> ?!
>>>> >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>>> >>
>>>> >> 
>>>> >>
>>>> >> This would be slightly more backcompatible than the currently
>>>> >> implemented proposal. Everything else I said remains true, and
>>>> >> I'm pretty sure most changes needed in packages would remain to
>>> be
>>>> done.
>>>> >>
>>>> >> Opinions ?
>>>> >>
>>>> >>
>>>> >>
>>>> >> > In some case where Rdevel now gives an error but did not
>>>> >> > previously, we could contemplate giving another "warning
>>>> >> > .... 'to become ERROR'" if there was too much breakage, though
>>>> >> > I don't expect that.
>>>> >>
>>>> >>
>>>> >> > For the R Core Team,
>>>> >>
>>>> >> > Martin Maechler,
>>>> >> > ETH Zurich
>>>> >>
>>>> >> ______________________________________________
>>>> >> [hidden email] mailing list
>>>> >> https://stat.ethz.ch/mailman/listinfo/rdevel>>>> >>
>>>>
>>>>
>>>>
>>>> > 
>>>> > Robin Hankin
>>>> > Neutral theorist
>>>> > [hidden email]
>>>>
>>>> > [[alternative HTML version deleted]]
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>
>>>
>>>
>>>
>>> 
>>> Gabriel Becker, PhD
>>> Associate Scientist (Bioinformatics)
>>> Genentech Research
>>>
>>> [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> [hidden email] mailing list
>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>
>>
>>
>
>
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Could we take a cue from min() and max()?
> x < 1:10
> min(x[x>7])
[1] 8
> min(x[x>11])
[1] Inf
Warning message:
In min(x[x > 11]) : no nonmissing arguments to min; returning Inf
>
As ?min says, this is implemented to preserve transitivity, and this
makes a lot of sense.
I think the issuing of a warning here is a good compromise; I can
always turn off warnings if I want.
I find this behaviour of min() and max() to be annoying in the *right*
way: it annoys me precisely when I need to be
annoyed, that is, when I haven't thought through the consequences of
sending zerolength arguments.
On Fri, Sep 9, 2016 at 6:00 AM, Paul Gilbert < [hidden email]> wrote:
>
>
> On 09/08/2016 01:22 PM, Gabriel Becker wrote:
>>
>> On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
>>
>>> Shouldn't binary operators (arithmetic and logical) should throw an error
>>> when one operand is NULL (or other type that doesn't make sense)? This
>>> is
>>> a different case than a zerolength operand of a legitimate type. E.g.,
>>> any(x < 0)
>>> should return FALSE if x is numberlike and length(x)==0 but give an
>>> error
>>> if x is NULL.
>>>
>> Bill,
>>
>> That is a good point. I can see the argument for this in the case that the
>> nonzero length is 1. I'm not sure which is better though. If we switch
>> any() to all(), things get murky.
>>
>> Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
>> all(x>0)), but the likelihood of this being a thoughtbug on the author's
>> part is exceedingly high, imho.
>
>
> I suspect there may be more R users than you think that understand and use
> vacuously true in code. I don't really like the idea of turning a perfectly
> good and properly documented mathematical test into an error in order to
> protect against a possible "thoughtbug".
>
> Paul
>
>
> So the desirable behavior seems to depend
>>
>> on the angle we look at it from.
>>
>> My personal opinion is that x < y with length(x)==0 should fail if
>> length(y)
>>>
>>> 1, at least, and I'd be for it being an error even if y is length 1,
>>
>> though I do acknowledge this is more likely (though still quite unlikely
>> imho) to be the intended behavior.
>>
>> ~G
>>
>>>
>>> I.e., I think the type check should be done before the length check.
>>>
>>>
>>> Bill Dunlap
>>> TIBCO Software
>>> wdunlap tibco.com
>>>
>>> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
>>> wrote:
>>>
>>>> Martin,
>>>>
>>>> Like Robin and Oliver I think this type of edgecase consistency is
>>>> important and that it's fantastic that Rcore  and you personally  are
>>>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>>>> this really does combine to go a long way to making R better and better.
>>>>
>>>> I do wonder a bit about the
>>>>
>>>> x = 1:2
>>>>
>>>> y = NULL
>>>>
>>>> x < y
>>>>
>>>> case.
>>>>
>>>> Returning a logical of length 0 is more backwards compatible, but is it
>>>> ever what the author actually intended? I have trouble thinking of a
>>>> case
>>>> where that lessthan didn't carry an implicit assumption that y was
>>>> nonNULL. I can say that in my own code, I've never hit that behavior
>>>> in
>>>> a
>>>> case that wasn't an error.
>>>>
>>>> My vote (unless someone else points out a compelling use for the
>>>> behavior)
>>>> is for the to throw an error. As a developer, I'd rather things like
>>>> this
>>>> break so the bug in my logic is visible, rather than propagating as the
>>>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>>>> subset, or (in the case it should be length 1) passed to if() (if throws
>>>> an
>>>> error now, but the rest would silently "work").
>>>>
>>>> Best,
>>>> ~G
>>>>
>>>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>>>> [hidden email]>
>>>> wrote:
>>>>
>>>>>>>>>> robin hankin < [hidden email]>
>>>>>>>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>>>>>
>>>>>
>>>>> > Martin I'd like to make a comment; I think that R's
>>>>> > behaviour on 'edge' cases like this is an important thing
>>>>> > and it's great that you are working on it.
>>>>>
>>>>> > I make heavy use of zeroextent arrays, chiefly because
>>>>> > the dimnames are an efficient and logical way to keep
>>>>> > track of certain types of information.
>>>>>
>>>>> > If I have, for example,
>>>>>
>>>>> > a < array(0,c(2,0,2))
>>>>> > dimnames(a) < list(name=c('Mike','Kevin'),
>>>>> NULL,item=c("hat","scarf"))
>>>>>
>>>>>
>>>>> > Then in R3.3.1, 70800 I get
>>>>>
>>>>> a> 0
>>>>> > logical(0)
>>>>> >>
>>>>>
>>>>> > But in 71219 I get
>>>>>
>>>>> a> 0
>>>>> > , , item = hat
>>>>>
>>>>>
>>>>> > name
>>>>> > Mike
>>>>> > Kevin
>>>>>
>>>>> > , , item = scarf
>>>>>
>>>>>
>>>>> > name
>>>>> > Mike
>>>>> > Kevin
>>>>>
>>>>> > (which is an empty logical array that holds the names of the
>>>>
>>>> people
>>>>>
>>>>> and
>>>>> > their clothes). I find the behaviour of 71219 very much
>>>>> preferable
>>>>> because
>>>>> > there is no reason to discard the information in the dimnames.
>>>>>
>>>>> Thanks a lot, Robin, (and Oliver) !
>>>>>
>>>>> Yes, the above is such a case where the new behavior makes much sense.
>>>>> And this behavior remains identical after the 71222 amendment.
>>>>>
>>>>> Martin
>>>>>
>>>>> > Best wishes
>>>>> > Robin
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>>>>> [hidden email]>
>>>>> > wrote:
>>>>>
>>>>> >> >>>>> Martin Maechler < [hidden email]>
>>>>> >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>>>> >>
>>>>> >> > Yesterday, changes to R's development version were committed,
>>>>> >> relating
>>>>> >> > to arithmetic, logic ('&' and '') and
>>>>> >> > comparison/relational ('<', '==') binary operators
>>>>> >> > which in NEWS are described as
>>>>> >>
>>>>> >> > SIGNIFICANT USERVISIBLE CHANGES:
>>>>> >>
>>>>> >> > [.............]
>>>>> >>
>>>>> >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>>>>> >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>>>>> >> > behave consistently, notably for arrays of length zero.
>>>>> >>
>>>>> >> > Arithmetic between length1 arrays and longer nonarrays had
>>>>> >> > silently dropped the array attributes and recycled. This
>>>>> >> > now gives a warning and will signal an error in the future,
>>>>> >> > as it has always for logic and comparison operations in
>>>>> >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>>>>> >> > ‘matrix(1,1) < 2:3’).
>>>>> >>
>>>>> >> > As the above "visually suggests" one could think of the
>>>>> changes
>>>>> >> > falling mainly two groups,
>>>>> >> > 1) <0extent array> (op) <nonarray>
>>>>> >> > 2) <1extent array> (arith) <nonarray of length != 1>
>>>>> >>
>>>>> >> > These changes are partly nonback compatible and may break
>>>>> >> > existing code. We believe that the internal consistency
>>>>> gained
>>>>> >> > from the changes is worth the few places with problems.
>>>>> >>
>>>>> >> > We expect some package maintainers (1020, or even more?) need
>>>>> >> > to adapt their code.
>>>>> >>
>>>>> >> > Case '2)' above mainly results in a new warning, e.g.,
>>>>> >>
>>>>> >> >> matrix(1,1) + 1:2
>>>>> >> > [1] 2 3
>>>>> >> > Warning message:
>>>>> >> > In matrix(1, 1) + 1:2 :
>>>>> >> > dropping dim() of array of length one. Will become ERROR
>>>>> >> >>
>>>>> >>
>>>>> >> > whereas '1)' gives errors in cases the result silently was a
>>>>> >> > vector of length zero, or also keeps array (dim & dimnames) in
>>>>> >> > cases these were silently dropped.
>>>>> >>
>>>>> >> > The following is a "heavily" commented R script showing (all
>>>>
>>>> ?)
>>>>>
>>>>> >> > the important cases with changes :
>>>>> >>
>>>>> >> > 
>>>>> >> 
>>>>> >>
>>>>> >> > (m < cbind(a=1[0], b=2[0]))
>>>>> >> > Lm < m; storage.mode(Lm) < "logical"
>>>>> >> > Im < m; storage.mode(Im) < "integer"
>>>>> >>
>>>>> >> > ## 1. 
>>>>> >> > try( m & NULL ) # in R <= 3.3.x :
>>>>> >> > ## Error in m & NULL :
>>>>> >> > ## operations are possible only for numeric, logical or
>>>>
>>>> complex
>>>>>
>>>>> >> types
>>>>> >> > ##
>>>>> >> > ## gives 'Lm' in R >= 3.4.0
>>>>> >>
>>>>> >> > ## 2. 
>>>>> >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>>>>> >> > Im + 2:3 ## gave integer(0), now remains matrix identical to
>>>>> Im
>>>>> >> (integer)
>>>>> >>
>>>>> >> > m > 1 ## gave logical(0), now remains matrix identical to
>>>>
>>>> Lm
>>>>>
>>>>> >> (logical)
>>>>> >> > m > 0.1[0] ## ditto
>>>>> >> > m > NULL ## ditto
>>>>> >>
>>>>> >> > ## 3. 
>>>>> >> > mm < m[,c(1:2,2:1,2)]
>>>>> >> > try( m == mm ) ## now gives error "nonconformable arrays",
>>>>> >> > ## but gave logical(0) in R <= 3.3.x
>>>>> >>
>>>>> >> > ## 4. 
>>>>> >> > str( Im + NULL) ## gave "num", now gives "int"
>>>>> >>
>>>>> >> > ## 5. 
>>>>> >> > ## special case for arithmetic w/ length1 array
>>>>> >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>>>>> >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>>>> >>
>>>>> >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>>>>> >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>>>>
>>>> match
>>>>>
>>>>> the
>>>>> >> length of object [2]
>>>>> >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>>>>> >> > ##
>>>>> >> > ## non0length arrays combined with {NULL or double() or ...}
>>>>> *fail*
>>>>> >>
>>>>> >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>>>>
>>>> array
>>>>>
>>>>> >> as scalar
>>>>> >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>>>>> >> warning to "be ERROR"
>>>>> >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>>>>
>>>> *error*
>>>>>
>>>>> >> now in R >= 3.4.0
>>>>> >> > tools::assertError(m1 & NULL) # gave and gives error
>>>>> >> > tools::assertError(m1  double())# ditto
>>>>> >> > ## m2 was slightly different:
>>>>> >> > tools::assertError(m2 + NULL)
>>>>> >> > tools::assertError(m2 & NULL)
>>>>> >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>>>>> above!
>>>>> >>
>>>>> >> > 
>>>>> >> 
>>>>> >>
>>>>> >>
>>>>> >> > Note that in R's own 'nls' sources, there was one case of
>>>>> >> > situation '2)' above, i.e. a 1x1matrix was used as a
>>>>
>>>> "scalar".
>>>>>
>>>>> >>
>>>>> >> > In such cases, you should explicitly coerce it to a vector,
>>>>> >> > either ("selfexplainingly") by as.vector(.), or as I did in
>>>>> >> > the nls case by c(.) : The latter is much less
>>>>> >> > selfexplaining, but nicer to read in mathematical formulae,
>>>>
>>>> and
>>>>>
>>>>> >> > currently also more efficient because it is a .Primitive.
>>>>> >>
>>>>> >> > Please use Rdevel with your code, and let us know if you see
>>>>> >> > effects that seem adverse.
>>>>> >>
>>>>> >> I've been slightly surprised (or even "frustrated") by the empty
>>>>> >> reaction on our Rdevel list to this post.
>>>>> >>
>>>>> >> I would have expected some critique, may be even some praise,
>>>>> >> ... in any case some sign people are "thinking along" (as we say
>>>>> >> in German).
>>>>> >>
>>>>> >> In the mean time, I've actually thought along the one case which
>>>>> >> is last above: The <op> (binary operation) between a
>>>>> >> non0length array and a 0length vector (and NULL which should
>>>>> >> be treated like a 0length vector):
>>>>> >>
>>>>> >> R <= 3.3.1 *is* quite inconsistent with these:
>>>>> >>
>>>>> >>
>>>>> >> and my proposal above (implemented in Rdevel, since Sep.5)
>>>>> would
>>>>> give an
>>>>> >> error for all these, but instead, R really could be more lenient
>>>>> here:
>>>>> >> A 0length result is ok, and it should *not* inherit the array
>>>>> >> (dim, dimnames), since the array is not of length 0. So instead
>>>>> >> of the above [for the very last part only!!], we would aim for
>>>>> >> the following. These *all* give an error in current Rdevel,
>>>>> >> with the exception of 'm1 + NULL' which "only" gives a "bad
>>>>> >> warning" :
>>>>> >>
>>>>> >> 
>>>>> >>
>>>>> >> m1 < matrix(1,1)
>>>>> >> m2 < matrix(1,2)
>>>>> >>
>>>>> >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>>>>> >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>>>>> >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to
>>>>> logical(0)
>>>>> ?!
>>>>> >> try(m1  double())# ERROR in R <= 3.3.x > change to
>>>>> logical(0)
>>>>> ?!
>>>>> >> ## m2 slightly different:
>>>>> >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>>>>
>>>> ?!
>>>>>
>>>>> >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>>>>
>>>> ?!
>>>>>
>>>>> >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>>>> >>
>>>>> >> 
>>>>> >>
>>>>> >> This would be slightly more backcompatible than the currently
>>>>> >> implemented proposal. Everything else I said remains true, and
>>>>> >> I'm pretty sure most changes needed in packages would remain to
>>>>
>>>> be
>>>>>
>>>>> done.
>>>>> >>
>>>>> >> Opinions ?
>>>>> >>
>>>>> >>
>>>>> >>
>>>>> >> > In some case where Rdevel now gives an error but did not
>>>>> >> > previously, we could contemplate giving another "warning
>>>>> >> > .... 'to become ERROR'" if there was too much breakage,
>>>>> though
>>>>> >> > I don't expect that.
>>>>> >>
>>>>> >>
>>>>> >> > For the R Core Team,
>>>>> >>
>>>>> >> > Martin Maechler,
>>>>> >> > ETH Zurich
>>>>> >>
>>>>> >> ______________________________________________
>>>>> >> [hidden email] mailing list
>>>>> >> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>> >>
>>>>>
>>>>>
>>>>>
>>>>> > 
>>>>> > Robin Hankin
>>>>> > Neutral theorist
>>>>> > [hidden email]
>>>>>
>>>>> > [[alternative HTML version deleted]]
>>>>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>
>>>>
>>>>
>>>>
>>>> 
>>>> Gabriel Becker, PhD
>>>> Associate Scientist (Bioinformatics)
>>>> Genentech Research
>>>>
>>>> [[alternative HTML version deleted]]
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>
>>>
>>>
>>
>>
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/rdevel
Robin Hankin
Neutral theorist
[hidden email]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Regarding Martin Maechler's proposal:
Arithmetic between length1 arrays and longer nonarrays had
silently dropped the array attributes and recycled. This now gives
a warning and will signal an error in the future, as it has always
for logic and comparison operations
For example, matrix(1,1,1) + (1:2) would give a warning/error.
I think this might be a mistake.
The potential benefits of this would be detection of some programming
errors, and increased consistency. The downsides are breaking
existing working programs, and decreased consistency.
Regarding consistency, the overall R philosophy is that attaching an
attribute to a vector doesn't change what you can do with it, or what
the result is, except that the result (often) gets the attributes
carried forward. By this logic, adding a 'dim' attribute shouldn't
stop you from doing arithmetic (or comparisons) that you otherwise
could.
But maybe 'dim' attributes are special? Well, they are in some
circumstances, and have to be when they are intended to change the
behaviour, such as when a matrix is used as an index with [.
But in many cases at present, 'dim' attributes DON'T stop you from
treating the object as a plain vector  for example, one is allowed
to do matrix(1:4,2,2)[3], and a<numeric(10); a[2:5]<matrix(1,2,2).
So it may make more sense to move towards consistency in the
permissive direction, rather than the restrictive direction. That
would mean allowing matrix(1,1,1)<(1:2), and maybe also things
like matrix(1,2,2)+(1:8).
Obviously, a change that removes error conditions is much less likely
to produce backwardscompatibility problems than a change that gives
errors for previouslyallowed operations.
And I think there would be some significant problems. In addition to
the 1020+ packages that Martin expects to break, there could be quite
a bit of user code that would no longer work  scripts for analysing
data sets that used to work, but now don't with the latest version.
There are reasons to expect such problems. Some operations such as
vector dot products using %*% produce results that are always scalar,
but are formed as 1x1 matrices. One can anticipate that many people
have not been getting rid of the 'dim' attribute in such cases, when
doing so hasn't been necessary in the past.
Regarding the 0length vector issue, I agree with other posters that
after a<numeric(0), is has to be allowable to write a<1. To not
allow this would be highly destructive of code reliability. And for
similar reason, after a<c(), a<1 needs to be allowed, which means
NULL<1 should be allowed (giving logical(0)), since c() is NULL.
Radford Neal
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


In reply to this post by R devel mailing list
Thank you, Gabe and Bill,
for taking up the discussion.
>>>>> William Dunlap < [hidden email]>
>>>>> on Thu, 8 Sep 2016 10:45:07 0700 writes:
> Prior to the mid1990s, S did "length0 OP lengthn > rep(NA, n)" and it
> was changed
> to "length0 OP lengthn > length0" to avoid lots of problems like
> any(x<0) being NA
> when length(x)==0. Yes, people could code defensively by putting lots of
> if(length(x)==0)...
> in their code, but that is tedious and errorprone and creates really ugly
> code.
Yes, so actually, basically
length0 OP <anything> > length0
Now the case of NULL that Bill mentioned.
I agree that NULL is not at all the same thing as double(0) or logical(0),
*but* there have been quite a few cases, where NULL is the
result of operations where "for consistency" double(0) / logical(0) should have
been.... and there are the users who use NULL as the equivalent
of those, e.g., by initializing a (to be grown, yes, very inefficient!)
vector with NULL instead of with say double(0).
For these reasons, many operations that expect a "numberlike"
(includes logical) atomic vector have treated NULL as such...
*and* parts of the {arith/logic/relop} OPs have done so already
in R "forever".
I still would argue that for these OPs, treating NULL as logical(0) {which
then may be promoted by the usual rules} is good thing.
> Is your suggestion to leave the length0 OP length1 case as it is but make
> length0 OP lengthtwoorhigher an error or warning (akin to the length2
> OP length3 case)?
That's exactly what one thing the current changes eliminated:
arithmetic (only; not logic, or relop) did treat the length1
case (for arrays!) different from the lengthGE2 case. And I strongly
believe that this is very wrong and counter to the predominant
recycling rules in (S and) R.
> By the way, the all(numeric(0)<0) is TRUE, as is all(numeric()>0), by de
> Morgan's rule, but that is not really relevant here.
> Bill Dunlap
> TIBCO Software
> wdunlap tibco.com
> On Thu, Sep 8, 2016 at 10:22 AM, Gabriel Becker < [hidden email]>
> wrote:
>>
>>
>> On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
>>
>>> Shouldn't binary operators (arithmetic and logical) should throw an error
>>> when one operand is NULL (or other type that doesn't make sense)? This is
>>> a different case than a zerolength operand of a legitimate type. E.g.,
>>> any(x < 0)
>>> should return FALSE if x is numberlike and length(x)==0 but give an
>>> error if x is NULL.
>>>
>> Bill,
>>
>> That is a good point. I can see the argument for this in the case that the
>> nonzero length is 1. I'm not sure which is better though. If we switch
>> any() to all(), things get murky.
>>
>> Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
>> all(x>0)), but the likelihood of this being a thoughtbug on the author's
>> part is exceedingly high, imho. So the desirable behavior seems to depend
>> on the angle we look at it from.
>>
>> My personal opinion is that x < y with length(x)==0 should fail if length(y)
>> > 1, at least, and I'd be for it being an error even if y is length 1,
>> though I do acknowledge this is more likely (though still quite unlikely
>> imho) to be the intended behavior.
>>
>> ~G
>>
>>>
>>> I.e., I think the type check should be done before the length check.
>>>
>>>
>>> Bill Dunlap
>>> TIBCO Software
>>> wdunlap tibco.com
>>>
>>> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
>>> wrote:
>>>
>>>> Martin,
>>>>
>>>> Like Robin and Oliver I think this type of edgecase consistency is
>>>> important and that it's fantastic that Rcore  and you personally  are
>>>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>>>> this really does combine to go a long way to making R better and better.
>>>>
>>>> I do wonder a bit about the
>>>>
>>>> x = 1:2
>>>>
>>>> y = NULL
>>>>
>>>> x < y
>>>>
>>>> case.
>>>>
>>>> Returning a logical of length 0 is more backwards compatible, but is it
>>>> ever what the author actually intended? I have trouble thinking of a case
>>>> where that lessthan didn't carry an implicit assumption that y was
>>>> nonNULL. I can say that in my own code, I've never hit that behavior
>>>> in a
>>>> case that wasn't an error.
>>>>
>>>> My vote (unless someone else points out a compelling use for the
>>>> behavior)
>>>> is for the to throw an error. As a developer, I'd rather things like this
>>>> break so the bug in my logic is visible, rather than propagating as the
>>>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>>>> subset, or (in the case it should be length 1) passed to if() (if throws
>>>> an
>>>> error now, but the rest would silently "work").
>>>>
>>>> Best,
>>>> ~G
>>>>
>>>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>>>> [hidden email]>
>>>> wrote:
>>>>
>>>> > >>>>> robin hankin < [hidden email]>
>>>> > >>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>>>> >
>>>> > > Martin I'd like to make a comment; I think that R's
>>>> > > behaviour on 'edge' cases like this is an important thing
>>>> > > and it's great that you are working on it.
>>>> >
>>>> > > I make heavy use of zeroextent arrays, chiefly because
>>>> > > the dimnames are an efficient and logical way to keep
>>>> > > track of certain types of information.
>>>> >
>>>> > > If I have, for example,
>>>> >
>>>> > > a < array(0,c(2,0,2))
>>>> > > dimnames(a) < list(name=c('Mike','Kevin'),
>>>> > NULL,item=c("hat","scarf"))
>>>> >
>>>> >
>>>> > > Then in R3.3.1, 70800 I get
>>>> >
>>>> > a> 0
>>>> > > logical(0)
>>>> > >>
>>>> >
>>>> > > But in 71219 I get
>>>> >
>>>> > a> 0
>>>> > > , , item = hat
>>>> >
>>>> >
>>>> > > name
>>>> > > Mike
>>>> > > Kevin
>>>> >
>>>> > > , , item = scarf
>>>> >
>>>> >
>>>> > > name
>>>> > > Mike
>>>> > > Kevin
>>>> >
>>>> > > (which is an empty logical array that holds the names of the
>>>> people
>>>> > and
>>>> > > their clothes). I find the behaviour of 71219 very much
>>>> preferable
>>>> > because
>>>> > > there is no reason to discard the information in the dimnames.
>>>> >
>>>> > Thanks a lot, Robin, (and Oliver) !
>>>> >
>>>> > Yes, the above is such a case where the new behavior makes much sense.
>>>> > And this behavior remains identical after the 71222 amendment.
>>>> >
>>>> > Martin
>>>> >
>>>> > > Best wishes
>>>> > > Robin
>>>> >
>>>> >
>>>> >
>>>> >
>>>> > > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>>>> > [hidden email]>
>>>> > > wrote:
>>>> >
>>>> > >> >>>>> Martin Maechler < [hidden email]>
>>>> > >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>>> > >>
>>>> > >> > Yesterday, changes to R's development version were committed,
>>>> > >> relating
>>>> > >> > to arithmetic, logic ('&' and '') and
>>>> > >> > comparison/relational ('<', '==') binary operators
>>>> > >> > which in NEWS are described as
>>>> > >>
>>>> > >> > SIGNIFICANT USERVISIBLE CHANGES:
>>>> > >>
>>>> > >> > [.............]
>>>> > >>
>>>> > >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>>>> > >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>>>> > >> > behave consistently, notably for arrays of length zero.
>>>> > >>
>>>> > >> > Arithmetic between length1 arrays and longer nonarrays had
>>>> > >> > silently dropped the array attributes and recycled. This
>>>> > >> > now gives a warning and will signal an error in the future,
>>>> > >> > as it has always for logic and comparison operations in
>>>> > >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>>>> > >> > ‘matrix(1,1) < 2:3’).
>>>> > >>
>>>> > >> > As the above "visually suggests" one could think of the
>>>> changes
>>>> > >> > falling mainly two groups,
>>>> > >> > 1) <0extent array> (op) <nonarray>
>>>> > >> > 2) <1extent array> (arith) <nonarray of length != 1>
>>>> > >>
>>>> > >> > These changes are partly nonback compatible and may break
>>>> > >> > existing code. We believe that the internal consistency
>>>> gained
>>>> > >> > from the changes is worth the few places with problems.
>>>> > >>
>>>> > >> > We expect some package maintainers (1020, or even more?) need
>>>> > >> > to adapt their code.
>>>> > >>
>>>> > >> > Case '2)' above mainly results in a new warning, e.g.,
>>>> > >>
>>>> > >> >> matrix(1,1) + 1:2
>>>> > >> > [1] 2 3
>>>> > >> > Warning message:
>>>> > >> > In matrix(1, 1) + 1:2 :
>>>> > >> > dropping dim() of array of length one. Will become ERROR
>>>> > >> >>
>>>> > >>
>>>> > >> > whereas '1)' gives errors in cases the result silently was a
>>>> > >> > vector of length zero, or also keeps array (dim & dimnames) in
>>>> > >> > cases these were silently dropped.
>>>> > >>
>>>> > >> > The following is a "heavily" commented R script showing (all
>>>> ?)
>>>> > >> > the important cases with changes :
>>>> > >>
>>>> > >> > 
>>>> > >> 
>>>> > >>
>>>> > >> > (m < cbind(a=1[0], b=2[0]))
>>>> > >> > Lm < m; storage.mode(Lm) < "logical"
>>>> > >> > Im < m; storage.mode(Im) < "integer"
>>>> > >>
>>>> > >> > ## 1. 
>>>> > >> > try( m & NULL ) # in R <= 3.3.x :
>>>> > >> > ## Error in m & NULL :
>>>> > >> > ## operations are possible only for numeric, logical or
>>>> complex
>>>> > >> types
>>>> > >> > ##
>>>> > >> > ## gives 'Lm' in R >= 3.4.0
>>>> > >>
>>>> > >> > ## 2. 
>>>> > >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>>>> > >> > Im + 2:3 ## gave integer(0), now remains matrix identical to
>>>> Im
>>>> > >> (integer)
>>>> > >>
>>>> > >> > m > 1 ## gave logical(0), now remains matrix identical
>>>> to Lm
>>>> > >> (logical)
>>>> > >> > m > 0.1[0] ## ditto
>>>> > >> > m > NULL ## ditto
>>>> > >>
>>>> > >> > ## 3. 
>>>> > >> > mm < m[,c(1:2,2:1,2)]
>>>> > >> > try( m == mm ) ## now gives error "nonconformable arrays",
>>>> > >> > ## but gave logical(0) in R <= 3.3.x
>>>> > >>
>>>> > >> > ## 4. 
>>>> > >> > str( Im + NULL) ## gave "num", now gives "int"
>>>> > >>
>>>> > >> > ## 5. 
>>>> > >> > ## special case for arithmetic w/ length1 array
>>>> > >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>>>> > >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>>> > >>
>>>> > >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>>>> > >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>>>> match
>>>> > the
>>>> > >> length of object [2]
>>>> > >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>>>> > >> > ##
>>>> > >> > ## non0length arrays combined with {NULL or double() or ...}
>>>> > *fail*
>>>> > >>
>>>> > >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>>>> array
>>>> > >> as scalar
>>>> > >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>>>> > >> warning to "be ERROR"
>>>> > >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>>>> *error*
>>>> > >> now in R >= 3.4.0
>>>> > >> > tools::assertError(m1 & NULL) # gave and gives error
>>>> > >> > tools::assertError(m1  double())# ditto
>>>> > >> > ## m2 was slightly different:
>>>> > >> > tools::assertError(m2 + NULL)
>>>> > >> > tools::assertError(m2 & NULL)
>>>> > >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>>>> > above!
>>>> > >>
>>>> > >> > 
>>>> > >> 
>>>> > >>
>>>> > >>
>>>> > >> > Note that in R's own 'nls' sources, there was one case of
>>>> > >> > situation '2)' above, i.e. a 1x1matrix was used as a
>>>> "scalar".
>>>> > >>
>>>> > >> > In such cases, you should explicitly coerce it to a vector,
>>>> > >> > either ("selfexplainingly") by as.vector(.), or as I did in
>>>> > >> > the nls case by c(.) : The latter is much less
>>>> > >> > selfexplaining, but nicer to read in mathematical formulae,
>>>> and
>>>> > >> > currently also more efficient because it is a .Primitive.
>>>> > >>
>>>> > >> > Please use Rdevel with your code, and let us know if you see
>>>> > >> > effects that seem adverse.
>>>> > >>
>>>> > >> I've been slightly surprised (or even "frustrated") by the empty
>>>> > >> reaction on our Rdevel list to this post.
>>>> > >>
>>>> > >> I would have expected some critique, may be even some praise,
>>>> > >> ... in any case some sign people are "thinking along" (as we say
>>>> > >> in German).
>>>> > >>
>>>> > >> In the mean time, I've actually thought along the one case which
>>>> > >> is last above: The <op> (binary operation) between a
>>>> > >> non0length array and a 0length vector (and NULL which should
>>>> > >> be treated like a 0length vector):
>>>> > >>
>>>> > >> R <= 3.3.1 *is* quite inconsistent with these:
>>>> > >>
>>>> > >>
>>>> > >> and my proposal above (implemented in Rdevel, since Sep.5)
>>>> would
>>>> > give an
>>>> > >> error for all these, but instead, R really could be more lenient
>>>> > here:
>>>> > >> A 0length result is ok, and it should *not* inherit the array
>>>> > >> (dim, dimnames), since the array is not of length 0. So instead
>>>> > >> of the above [for the very last part only!!], we would aim for
>>>> > >> the following. These *all* give an error in current Rdevel,
>>>> > >> with the exception of 'm1 + NULL' which "only" gives a "bad
>>>> > >> warning" :
>>>> > >>
>>>> > >> 
>>>> > >>
>>>> > >> m1 < matrix(1,1)
>>>> > >> m2 < matrix(1,2)
>>>> > >>
>>>> > >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>>>> > >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>>>> > >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to
>>>> logical(0)
>>>> > ?!
>>>> > >> try(m1  double())# ERROR in R <= 3.3.x > change to
>>>> logical(0)
>>>> > ?!
>>>> > >> ## m2 slightly different:
>>>> > >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>>>> ?!
>>>> > >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to
>>>> logical(0) ?!
>>>> > >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>>> > >>
>>>> > >> 
>>>> > >>
>>>> > >> This would be slightly more backcompatible than the currently
>>>> > >> implemented proposal. Everything else I said remains true, and
>>>> > >> I'm pretty sure most changes needed in packages would remain to
>>>> be
>>>> > done.
>>>> > >>
>>>> > >> Opinions ?
>>>> > >>
>>>> > >>
>>>> > >>
>>>> > >> > In some case where Rdevel now gives an error but did not
>>>> > >> > previously, we could contemplate giving another "warning
>>>> > >> > .... 'to become ERROR'" if there was too much breakage,
>>>> though
>>>> > >> > I don't expect that.
>>>> > >>
>>>> > >>
>>>> > >> > For the R Core Team,
>>>> > >>
>>>> > >> > Martin Maechler,
>>>> > >> > ETH Zurich
>>>> > >>
>>>> > >> ______________________________________________
>>>> > >> [hidden email] mailing list
>>>> > >> https://stat.ethz.ch/mailman/listinfo/rdevel >>>> > >>
>>>> >
>>>> >
>>>> >
>>>> > > 
>>>> > > Robin Hankin
>>>> > > Neutral theorist
>>>> > > [hidden email]
>>>> >
>>>> > > [[alternative HTML version deleted]]
>>>> >
>>>> > ______________________________________________
>>>> > [hidden email] mailing list
>>>> > https://stat.ethz.ch/mailman/listinfo/rdevel >>>> >
>>>>
>>>>
>>>>
>>>> 
>>>> Gabriel Becker, PhD
>>>> Associate Scientist (Bioinformatics)
>>>> Genentech Research
>>>>
>>>> [[alternative HTML version deleted]]
>>>>
>>>> ______________________________________________
>>>> [hidden email] mailing list
>>>> https://stat.ethz.ch/mailman/listinfo/rdevel >>>>
>>>
>>>
>>
>>
>> 
>> Gabriel Becker, PhD
>> Associate Scientist (Bioinformatics)
>> Genentech Research
>>
> [[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Radford Neal < [hidden email]>
>>>>> on Thu, 8 Sep 2016 17:11:18 0400 writes:
> Regarding Martin Maechler's proposal:
> Arithmetic between length1 arrays and longer nonarrays had
> silently dropped the array attributes and recycled. This now gives
> a warning and will signal an error in the future, as it has always
> for logic and comparison operations
> For example, matrix(1,1,1) + (1:2) would give a warning/error.
> I think this might be a mistake.
> The potential benefits of this would be detection of some programming
> errors, and increased consistency. The downsides are breaking
> existing working programs, and decreased consistency.
> Regarding consistency, the overall R philosophy is that attaching an
> attribute to a vector doesn't change what you can do with it, or what
> the result is, except that the result (often) gets the attributes
> carried forward. By this logic, adding a 'dim' attribute shouldn't
> stop you from doing arithmetic (or comparisons) that you otherwise
> could.
Thank you, Radford, for joining in.
The above is a good line of reasoning.
> But maybe 'dim' attributes are special? Well, they are in some
> circumstances, and have to be when they are intended to change the
> behaviour, such as when a matrix is used as an index with [.
indeed.
> But in many cases at present, 'dim' attributes DON'T stop you from
> treating the object as a plain vector  for example, one is allowed
> to do matrix(1:4,2,2)[3], and a<numeric(10); a[2:5]<matrix(1,2,2).
agreed.
> So it may make more sense to move towards consistency in the
> permissive direction, rather than the restrictive direction.
> That would mean allowing matrix(1,1,1) < (1:2), and maybe also things
> like matrix(1,2,2)+(1:8).
That is an interesting idea. Yes, in my view that would
definitely also have to allow the latter, by the above argument
of not treating the dim/dimnames attributes special. For
nonarrays length1 is not treated much special apart from the
fact that length1 can always be recycled (without warning).
> Obviously, a change that removes error conditions is much less likely
> to produce backwardscompatibility problems than a change that gives
> errors for previouslyallowed operations.
Of course that is true... and that has also been the reason for
my amendment
> And I think there would be some significant problems. In addition to
> the 1020+ packages that Martin expects to break, there could be quite
> a bit of user code that would no longer work  scripts for analysing
> data sets that used to work, but now don't with the latest version.
That's not true (at least for the cases above): They would give
a strong warning, "strong" because it is
> matrix(1,1) + 1:2
[1] 2 3
Warning message:
In matrix(1, 1) + 1:2 :
dropping dim() of array of length one. Will become ERROR
>
*and* the logic and relop versions of this, e.g.,
matrix(TRUE,1)  c(TRUE,FALSE) ; matrix(1,1) > 1:2,
have always been an error; so nothing would break there.
> There are reasons to expect such problems. Some operations such as
> vector dot products using %*% produce results that are always scalar,
> but are formed as 1x1 matrices.
Of course; that *was* the reason the very special treatment for arithmetic
length1 arrays had been introduced. It is convenient.
However, *some* of the conveniences in S (and hence R) functions
have been dangerous {and much more used, hence close to
impossible to abolish, e.g., sample(x) when x is numeric of length 1,
and several others, you'll find in the "R Inferno"}, or at least
quirky for *programming* with R (as opposed to pure interactive use).
> One can anticipate that many people
> have not been getting rid of the 'dim' attribute in such cases, when
> doing so hasn't been necessary in the past.
If it remains at 1020 CRAN packages (out of 9000), each with
just very few instances, that would indicate I think not so wide
spread use.
Note that they only did not have to get rid of the dim() in the
length1 case (and only for arithmetic): as soon as they had
another dimension, they would have got an error.
Still, I agree about the validity of your line of thought, and
that in order to get consistency we also could go into the
direction of being more permissive rather than restrictive.
I'm interested to hear other opinions notably as in recent years,
some famous R teachers have typically critized R are as being
not strict enough ...
> Regarding the 0length vector issue, I agree with other posters that
> after a<numeric(0), is has to be allowable to write a<1. To not
> allow this would be highly destructive of code reliability. And for
> similar reason, after a<c(), a<1 needs to be allowed, which means
> NULL<1 should be allowed (giving logical(0)), since c() is
> NULL.
Yes, indeed, treating NULL the same as a length0 atomic
vector here is also correct in my view, and maybe the fact you
mention that c() is NULL does help to convince others.
Martin
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


> Radford Nea:
> > So it may make more sense to move towards consistency in the
> > permissive direction, rather than the restrictive direction.
>
> > That would mean allowing matrix(1,1,1) < (1:2), and maybe also things
> > like matrix(1,2,2)+(1:8).
>
> Martin Maechler:
> That is an interesting idea. Yes, in my view that would
> definitely also have to allow the latter, by the above argument
> of not treating the dim/dimnames attributes special. For
> nonarrays length1 is not treated much special apart from the
> fact that length1 can always be recycled (without warning).
I think one could argue for allowing matrix(1,1,1)+(1:8) but not
matrix(1,2,2)+(1:8). Length1 vectors certainly are special in some
circumstances, being R's only way of representing a scalar. For
instance, if (c(T,F)) gives a warning.
This really goes back to what I think may have been a basic mistake in
the design of S, in deciding that everything is a vector, then halfway
modifying this with dim attributes, but it's too late to totally undo
that (though allowing a 0length dim attribute to explicitly mark a
length1 vector as a scalar might help).
> > And I think there would be some significant problems. In addition to
> > the 1020+ packages that Martin expects to break, there could be quite
> > a bit of user code that would no longer work  scripts for analysing
> > data sets that used to work, but now don't with the latest version.
>
> That's not true (at least for the cases above): They would give
> a strong warning
But isn't the intent to make it an error later? So I assume we're
debating making it an error, not just a warning. (Though I'm
generally opposed to such warnings anyway, unless they could somehow
be restricted to come up only for interactive uses, not from deep in a
program the user didn't write, making them totally mysterious...)
> *and* the logic and relop versions of this, e.g.,
> matrix(TRUE,1)  c(TRUE,FALSE) ; matrix(1,1) > 1:2,
> have always been an error; so nothing would break there.
Yes, that wouldn't change the behaviour of old code, but if we're
aiming for consistencey, it might make sense to get rid of that error,
allowing code like sum(a%*%b<c(10,20,30)) with a and b being vectors,
rather than forcing the programmer to write sum(c(a%*%b)<c(10,20,30)).
> Of course; that *was* the reason the very special treatment for arithmetic
> length1 arrays had been introduced. It is convenient.
>
> However, *some* of the conveniences in S (and hence R) functions
> have been dangerous {and much more used, hence close to
> impossible to abolish, e.g., sample(x) when x is numeric of length 1,
There's a difference between these two. Giving an error when using a
1x1 matrix as a scalar may detect some programming bugs, but not
giving an error doesn't introduce a bug. Whereas sample(2:n) behaving
differently when n is 2 than when n is greater than 2 is itself a bug,
that the programmer has to consciously avoid by being aware of the quirk.
Radford Neal
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


On 09/08/2016 05:06 PM, robin hankin wrote:
> Could we take a cue from min() and max()?
>
>> x < 1:10
>> min(x[x>7])
> [1] 8
>> min(x[x>11])
> [1] Inf
> Warning message:
> In min(x[x > 11]) : no nonmissing arguments to min; returning Inf
>>
>
> As ?min says, this is implemented to preserve transitivity, and this
> makes a lot of sense.
> I think the issuing of a warning here is a good compromise; I can
> always turn off warnings if I want.
I fear you are thinking of this as an end user, rather than as a package
developer. Warnings are for end users, when they do something they
possibly should be warned about. A package really should not generate
warnings unless they are for end user consumption. In package
development I treat warnings the same way I treat errors: build fails,
program around it. So what you call a compromise is no compromise at all
as far as I am concerned.
But perhaps there is a use for an end user version, maybe All() or ALL()
that issues an error or warning. There are a lot of functions and
operators in R that could warn about mistakes that a user may be making.
Paul
>
> I find this behaviour of min() and max() to be annoying in the *right*
> way: it annoys me precisely when I need to be
> annoyed, that is, when I haven't thought through the consequences of
> sending zerolength arguments.
>
>
> On Fri, Sep 9, 2016 at 6:00 AM, Paul Gilbert < [hidden email]> wrote:
>>
>>
>> On 09/08/2016 01:22 PM, Gabriel Becker wrote:
>>>
>>> On Thu, Sep 8, 2016 at 10:05 AM, William Dunlap < [hidden email]> wrote:
>>>
>>>> Shouldn't binary operators (arithmetic and logical) should throw an error
>>>> when one operand is NULL (or other type that doesn't make sense)? This
>>>> is
>>>> a different case than a zerolength operand of a legitimate type. E.g.,
>>>> any(x < 0)
>>>> should return FALSE if x is numberlike and length(x)==0 but give an
>>>> error
>>>> if x is NULL.
>>>>
>>> Bill,
>>>
>>> That is a good point. I can see the argument for this in the case that the
>>> nonzero length is 1. I'm not sure which is better though. If we switch
>>> any() to all(), things get murky.
>>>
>>> Mathematically, all(x<0) is TRUE if x is length 0 (as are all(x==0), and
>>> all(x>0)), but the likelihood of this being a thoughtbug on the author's
>>> part is exceedingly high, imho.
>>
>>
>> I suspect there may be more R users than you think that understand and use
>> vacuously true in code. I don't really like the idea of turning a perfectly
>> good and properly documented mathematical test into an error in order to
>> protect against a possible "thoughtbug".
>>
>> Paul
>>
>>
>> So the desirable behavior seems to depend
>>>
>>> on the angle we look at it from.
>>>
>>> My personal opinion is that x < y with length(x)==0 should fail if
>>> length(y)
>>>>
>>>> 1, at least, and I'd be for it being an error even if y is length 1,
>>>
>>> though I do acknowledge this is more likely (though still quite unlikely
>>> imho) to be the intended behavior.
>>>
>>> ~G
>>>
>>>>
>>>> I.e., I think the type check should be done before the length check.
>>>>
>>>>
>>>> Bill Dunlap
>>>> TIBCO Software
>>>> wdunlap tibco.com
>>>>
>>>> On Thu, Sep 8, 2016 at 8:43 AM, Gabriel Becker < [hidden email]>
>>>> wrote:
>>>>
>>>>> Martin,
>>>>>
>>>>> Like Robin and Oliver I think this type of edgecase consistency is
>>>>> important and that it's fantastic that Rcore  and you personally  are
>>>>> willing to tackle some of these "gotcha" behaviors. "Little" stuff like
>>>>> this really does combine to go a long way to making R better and better.
>>>>>
>>>>> I do wonder a bit about the
>>>>>
>>>>> x = 1:2
>>>>>
>>>>> y = NULL
>>>>>
>>>>> x < y
>>>>>
>>>>> case.
>>>>>
>>>>> Returning a logical of length 0 is more backwards compatible, but is it
>>>>> ever what the author actually intended? I have trouble thinking of a
>>>>> case
>>>>> where that lessthan didn't carry an implicit assumption that y was
>>>>> nonNULL. I can say that in my own code, I've never hit that behavior
>>>>> in
>>>>> a
>>>>> case that wasn't an error.
>>>>>
>>>>> My vote (unless someone else points out a compelling use for the
>>>>> behavior)
>>>>> is for the to throw an error. As a developer, I'd rather things like
>>>>> this
>>>>> break so the bug in my logic is visible, rather than propagating as the
>>>>> 0length logical is &'ed or 'ed with other logical vectors, or used to
>>>>> subset, or (in the case it should be length 1) passed to if() (if throws
>>>>> an
>>>>> error now, but the rest would silently "work").
>>>>>
>>>>> Best,
>>>>> ~G
>>>>>
>>>>> On Thu, Sep 8, 2016 at 3:49 AM, Martin Maechler <
>>>>> [hidden email]>
>>>>> wrote:
>>>>>
>>>>>>>>>>> robin hankin < [hidden email]>
>>>>>>>>>>> on Thu, 8 Sep 2016 10:05:21 +1200 writes:
>>>>>>
>>>>>>
>>>>>> > Martin I'd like to make a comment; I think that R's
>>>>>> > behaviour on 'edge' cases like this is an important thing
>>>>>> > and it's great that you are working on it.
>>>>>>
>>>>>> > I make heavy use of zeroextent arrays, chiefly because
>>>>>> > the dimnames are an efficient and logical way to keep
>>>>>> > track of certain types of information.
>>>>>>
>>>>>> > If I have, for example,
>>>>>>
>>>>>> > a < array(0,c(2,0,2))
>>>>>> > dimnames(a) < list(name=c('Mike','Kevin'),
>>>>>> NULL,item=c("hat","scarf"))
>>>>>>
>>>>>>
>>>>>> > Then in R3.3.1, 70800 I get
>>>>>>
>>>>>> a> 0
>>>>>> > logical(0)
>>>>>> >>
>>>>>>
>>>>>> > But in 71219 I get
>>>>>>
>>>>>> a> 0
>>>>>> > , , item = hat
>>>>>>
>>>>>>
>>>>>> > name
>>>>>> > Mike
>>>>>> > Kevin
>>>>>>
>>>>>> > , , item = scarf
>>>>>>
>>>>>>
>>>>>> > name
>>>>>> > Mike
>>>>>> > Kevin
>>>>>>
>>>>>> > (which is an empty logical array that holds the names of the
>>>>>
>>>>> people
>>>>>>
>>>>>> and
>>>>>> > their clothes). I find the behaviour of 71219 very much
>>>>>> preferable
>>>>>> because
>>>>>> > there is no reason to discard the information in the dimnames.
>>>>>>
>>>>>> Thanks a lot, Robin, (and Oliver) !
>>>>>>
>>>>>> Yes, the above is such a case where the new behavior makes much sense.
>>>>>> And this behavior remains identical after the 71222 amendment.
>>>>>>
>>>>>> Martin
>>>>>>
>>>>>> > Best wishes
>>>>>> > Robin
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> > On Wed, Sep 7, 2016 at 9:49 PM, Martin Maechler <
>>>>>> [hidden email]>
>>>>>> > wrote:
>>>>>>
>>>>>> >> >>>>> Martin Maechler < [hidden email]>
>>>>>> >> >>>>> on Tue, 6 Sep 2016 22:26:31 +0200 writes:
>>>>>> >>
>>>>>> >> > Yesterday, changes to R's development version were committed,
>>>>>> >> relating
>>>>>> >> > to arithmetic, logic ('&' and '') and
>>>>>> >> > comparison/relational ('<', '==') binary operators
>>>>>> >> > which in NEWS are described as
>>>>>> >>
>>>>>> >> > SIGNIFICANT USERVISIBLE CHANGES:
>>>>>> >>
>>>>>> >> > [.............]
>>>>>> >>
>>>>>> >> > • Arithmetic, logic (‘&’, ‘’) and comparison (aka
>>>>>> >> > ‘relational’, e.g., ‘<’, ‘==’) operations with arrays now
>>>>>> >> > behave consistently, notably for arrays of length zero.
>>>>>> >>
>>>>>> >> > Arithmetic between length1 arrays and longer nonarrays had
>>>>>> >> > silently dropped the array attributes and recycled. This
>>>>>> >> > now gives a warning and will signal an error in the future,
>>>>>> >> > as it has always for logic and comparison operations in
>>>>>> >> > these cases (e.g., compare ‘matrix(1,1) + 2:3’ and
>>>>>> >> > ‘matrix(1,1) < 2:3’).
>>>>>> >>
>>>>>> >> > As the above "visually suggests" one could think of the
>>>>>> changes
>>>>>> >> > falling mainly two groups,
>>>>>> >> > 1) <0extent array> (op) <nonarray>
>>>>>> >> > 2) <1extent array> (arith) <nonarray of length != 1>
>>>>>> >>
>>>>>> >> > These changes are partly nonback compatible and may break
>>>>>> >> > existing code. We believe that the internal consistency
>>>>>> gained
>>>>>> >> > from the changes is worth the few places with problems.
>>>>>> >>
>>>>>> >> > We expect some package maintainers (1020, or even more?) need
>>>>>> >> > to adapt their code.
>>>>>> >>
>>>>>> >> > Case '2)' above mainly results in a new warning, e.g.,
>>>>>> >>
>>>>>> >> >> matrix(1,1) + 1:2
>>>>>> >> > [1] 2 3
>>>>>> >> > Warning message:
>>>>>> >> > In matrix(1, 1) + 1:2 :
>>>>>> >> > dropping dim() of array of length one. Will become ERROR
>>>>>> >> >>
>>>>>> >>
>>>>>> >> > whereas '1)' gives errors in cases the result silently was a
>>>>>> >> > vector of length zero, or also keeps array (dim & dimnames) in
>>>>>> >> > cases these were silently dropped.
>>>>>> >>
>>>>>> >> > The following is a "heavily" commented R script showing (all
>>>>>
>>>>> ?)
>>>>>>
>>>>>> >> > the important cases with changes :
>>>>>> >>
>>>>>> >> > 
>>>>>> >> 
>>>>>> >>
>>>>>> >> > (m < cbind(a=1[0], b=2[0]))
>>>>>> >> > Lm < m; storage.mode(Lm) < "logical"
>>>>>> >> > Im < m; storage.mode(Im) < "integer"
>>>>>> >>
>>>>>> >> > ## 1. 
>>>>>> >> > try( m & NULL ) # in R <= 3.3.x :
>>>>>> >> > ## Error in m & NULL :
>>>>>> >> > ## operations are possible only for numeric, logical or
>>>>>
>>>>> complex
>>>>>>
>>>>>> >> types
>>>>>> >> > ##
>>>>>> >> > ## gives 'Lm' in R >= 3.4.0
>>>>>> >>
>>>>>> >> > ## 2. 
>>>>>> >> > m + 2:3 ## gave numeric(0), now remains matrix identical to m
>>>>>> >> > Im + 2:3 ## gave integer(0), now remains matrix identical to
>>>>>> Im
>>>>>> >> (integer)
>>>>>> >>
>>>>>> >> > m > 1 ## gave logical(0), now remains matrix identical to
>>>>>
>>>>> Lm
>>>>>>
>>>>>> >> (logical)
>>>>>> >> > m > 0.1[0] ## ditto
>>>>>> >> > m > NULL ## ditto
>>>>>> >>
>>>>>> >> > ## 3. 
>>>>>> >> > mm < m[,c(1:2,2:1,2)]
>>>>>> >> > try( m == mm ) ## now gives error "nonconformable arrays",
>>>>>> >> > ## but gave logical(0) in R <= 3.3.x
>>>>>> >>
>>>>>> >> > ## 4. 
>>>>>> >> > str( Im + NULL) ## gave "num", now gives "int"
>>>>>> >>
>>>>>> >> > ## 5. 
>>>>>> >> > ## special case for arithmetic w/ length1 array
>>>>>> >> > (m1 < matrix(1,1,1, dimnames=list("Ro","col")))
>>>>>> >> > (m2 < matrix(1,2,1, dimnames=list(c("A","B"),"col")))
>>>>>> >>
>>>>>> >> > m1 + 1:2 # > 2:3 but now with warning to "become ERROR"
>>>>>> >> > tools::assertError(m1 & 1:2)# ERR: dims [product 1] do not
>>>>>
>>>>> match
>>>>>>
>>>>>> the
>>>>>> >> length of object [2]
>>>>>> >> > tools::assertError(m1 < 1:2)# ERR: (ditto)
>>>>>> >> > ##
>>>>>> >> > ## non0length arrays combined with {NULL or double() or ...}
>>>>>> *fail*
>>>>>> >>
>>>>>> >> > ### Length1 arrays: Arithmetic with vectors > 1 treated
>>>>>
>>>>> array
>>>>>>
>>>>>> >> as scalar
>>>>>> >> > m1 + NULL # gave numeric(0) in R <= 3.3.x  still, *but* w/
>>>>>> >> warning to "be ERROR"
>>>>>> >> > try(m1 > NULL) # gave logical(0) in R <= 3.3.x  an
>>>>>
>>>>> *error*
>>>>>>
>>>>>> >> now in R >= 3.4.0
>>>>>> >> > tools::assertError(m1 & NULL) # gave and gives error
>>>>>> >> > tools::assertError(m1  double())# ditto
>>>>>> >> > ## m2 was slightly different:
>>>>>> >> > tools::assertError(m2 + NULL)
>>>>>> >> > tools::assertError(m2 & NULL)
>>>>>> >> > try(m2 == NULL) ## was logical(0) in R <= 3.3.x; now error as
>>>>>> above!
>>>>>> >>
>>>>>> >> > 
>>>>>> >> 
>>>>>> >>
>>>>>> >>
>>>>>> >> > Note that in R's own 'nls' sources, there was one case of
>>>>>> >> > situation '2)' above, i.e. a 1x1matrix was used as a
>>>>>
>>>>> "scalar".
>>>>>>
>>>>>> >>
>>>>>> >> > In such cases, you should explicitly coerce it to a vector,
>>>>>> >> > either ("selfexplainingly") by as.vector(.), or as I did in
>>>>>> >> > the nls case by c(.) : The latter is much less
>>>>>> >> > selfexplaining, but nicer to read in mathematical formulae,
>>>>>
>>>>> and
>>>>>>
>>>>>> >> > currently also more efficient because it is a .Primitive.
>>>>>> >>
>>>>>> >> > Please use Rdevel with your code, and let us know if you see
>>>>>> >> > effects that seem adverse.
>>>>>> >>
>>>>>> >> I've been slightly surprised (or even "frustrated") by the empty
>>>>>> >> reaction on our Rdevel list to this post.
>>>>>> >>
>>>>>> >> I would have expected some critique, may be even some praise,
>>>>>> >> ... in any case some sign people are "thinking along" (as we say
>>>>>> >> in German).
>>>>>> >>
>>>>>> >> In the mean time, I've actually thought along the one case which
>>>>>> >> is last above: The <op> (binary operation) between a
>>>>>> >> non0length array and a 0length vector (and NULL which should
>>>>>> >> be treated like a 0length vector):
>>>>>> >>
>>>>>> >> R <= 3.3.1 *is* quite inconsistent with these:
>>>>>> >>
>>>>>> >>
>>>>>> >> and my proposal above (implemented in Rdevel, since Sep.5)
>>>>>> would
>>>>>> give an
>>>>>> >> error for all these, but instead, R really could be more lenient
>>>>>> here:
>>>>>> >> A 0length result is ok, and it should *not* inherit the array
>>>>>> >> (dim, dimnames), since the array is not of length 0. So instead
>>>>>> >> of the above [for the very last part only!!], we would aim for
>>>>>> >> the following. These *all* give an error in current Rdevel,
>>>>>> >> with the exception of 'm1 + NULL' which "only" gives a "bad
>>>>>> >> warning" :
>>>>>> >>
>>>>>> >> 
>>>>>> >>
>>>>>> >> m1 < matrix(1,1)
>>>>>> >> m2 < matrix(1,2)
>>>>>> >>
>>>>>> >> m1 + NULL # numeric(0) in R <= 3.3.x > OK ?!
>>>>>> >> m1 > NULL # logical(0) in R <= 3.3.x > OK ?!
>>>>>> >> try(m1 & NULL) # ERROR in R <= 3.3.x > change to
>>>>>> logical(0)
>>>>>> ?!
>>>>>> >> try(m1  double())# ERROR in R <= 3.3.x > change to
>>>>>> logical(0)
>>>>>> ?!
>>>>>> >> ## m2 slightly different:
>>>>>> >> try(m2 + NULL) # ERROR in R <= 3.3.x > change to double(0)
>>>>>
>>>>> ?!
>>>>>>
>>>>>> >> try(m2 & NULL) # ERROR in R <= 3.3.x > change to logical(0)
>>>>>
>>>>> ?!
>>>>>>
>>>>>> >> m2 == NULL # logical(0) in R <= 3.3.x > OK ?!
>>>>>> >>
>>>>>> >> 
>>>>>> >>
>>>>>> >> This would be slightly more backcompatible than the currently
>>>>>> >> implemented proposal. Everything else I said remains true, and
>>>>>> >> I'm pretty sure most changes needed in packages would remain to
>>>>>
>>>>> be
>>>>>>
>>>>>> done.
>>>>>> >>
>>>>>> >> Opinions ?
>>>>>> >>
>>>>>> >>
>>>>>> >>
>>>>>> >> > In some case where Rdevel now gives an error but did not
>>>>>> >> > previously, we could contemplate giving another "warning
>>>>>> >> > .... 'to become ERROR'" if there was too much breakage,
>>>>>> though
>>>>>> >> > I don't expect that.
>>>>>> >>
>>>>>> >>
>>>>>> >> > For the R Core Team,
>>>>>> >>
>>>>>> >> > Martin Maechler,
>>>>>> >> > ETH Zurich
>>>>>> >>
>>>>>> >> ______________________________________________
>>>>>> >> [hidden email] mailing list
>>>>>> >> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>> >>
>>>>>>
>>>>>>
>>>>>>
>>>>>> > 
>>>>>> > Robin Hankin
>>>>>> > Neutral theorist
>>>>>> > [hidden email]
>>>>>>
>>>>>> > [[alternative HTML version deleted]]
>>>>>>
>>>>>> ______________________________________________
>>>>>> [hidden email] mailing list
>>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>>
>>>>>
>>>>>
>>>>>
>>>>> 
>>>>> Gabriel Becker, PhD
>>>>> Associate Scientist (Bioinformatics)
>>>>> Genentech Research
>>>>>
>>>>> [[alternative HTML version deleted]]
>>>>>
>>>>> ______________________________________________
>>>>> [hidden email] mailing list
>>>>> https://stat.ethz.ch/mailman/listinfo/rdevel>>>>>
>>>>
>>>>
>>>
>>>
>>
>> ______________________________________________
>> [hidden email] mailing list
>> https://stat.ethz.ch/mailman/listinfo/rdevel>
>
>
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


Martin et al.,
I seem to be in the minority here, so I won't belabor the point too much,
but one last response inline:
On Thu, Sep 8, 2016 at 11:51 PM, Martin Maechler < [hidden email]
> wrote:
> Thank you, Gabe and Bill,
>
> for taking up the discussion.
>
> >>>>> William Dunlap < [hidden email]>
> >>>>> on Thu, 8 Sep 2016 10:45:07 0700 writes:
>
> > Prior to the mid1990s, S did "length0 OP lengthn > rep(NA, n)"
> and it
> > was changed
> > to "length0 OP lengthn > length0" to avoid lots of problems like
> > any(x<0) being NA
> > when length(x)==0. Yes, people could code defensively by putting
> lots of
> > if(length(x)==0)...
> > in their code, but that is tedious and errorprone and creates
> really ugly
> > code.
>
> Yes, so actually, basically
>
> length0 OP <anything> > length0
>
> Now the case of NULL that Bill mentioned.
> I agree that NULL is not at all the same thing as double(0) or
> logical(0),
> *but* there have been quite a few cases, where NULL is the
> result of operations where "for consistency" double(0) / logical(0)
> should have
> been.... and there are the users who use NULL as the equivalent
> of those, e.g., by initializing a (to be grown, yes, very inefficient!)
> vector with NULL instead of with say double(0).
>
> For these reasons, many operations that expect a "numberlike"
> (includes logical) atomic vector have treated NULL as such...
> *and* parts of the {arith/logic/relop} OPs have done so already
> in R "forever".
> I still would argue that for these OPs, treating NULL as logical(0) {which
> then may be promoted by the usual rules} is good thing.
>
>
> > Is your suggestion to leave the length0 OP length1 case as it is
> but make
> > length0 OP lengthtwoorhigher an error or warning (akin to the
> length2
> > OP length3 case)?
>
> That's exactly what one thing the current changes eliminated:
> arithmetic (only; not logic, or relop) did treat the length1
> case (for arrays!) different from the lengthGE2 case. And I strongly
> believe that this is very wrong and counter to the predominant
> recycling rules in (S and) R.
>
In my view, the recycling rules apply first and foremost to pairs of
vectors of lengths n,m >=1. And they can be semantically explained in that
case very easily: "the shorter, nonzerolength vector is rep'ed out to be
the length of the longer vector and then (generally) an element wise
operation takes place". The zerolength behavior already does not adhere to
this definition, as it would be impossible to do in the case of a
zerolength vector and a nonzerolength vector.
So the zerolength recycling behavior is already specialcased as I
understand it. In light of that, it seems that it would be allowable to
have different behavior based on the length of the other vector.
Furthermore, while I acknowledge the usefulness of the
x = numeric()
x < 5
case (i.e., the other vector is length 1), I can't come up with any use of,
e.g.,
y = numeric()
y < 3:5
That I can make any sense of other than as a violation of implicit
assumptions by the coder about the length of y.
Thus, I still think that should at *least* warn, preferably (imho) give an
error.
Best,
~G

Gabriel Becker, PhD
Associate Scientist (Bioinformatics)
Genentech Research
[[alternative HTML version deleted]]
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


>>>>> Radford Neal < [hidden email]>
>>>>> on Fri, 9 Sep 2016 10:29:14 0400 writes:
>> Radford Nea:
>> > So it may make more sense to move towards consistency in the
>> > permissive direction, rather than the restrictive direction.
>>
>> > That would mean allowing matrix(1,1,1) < (1:2), and maybe also things
>> > like matrix(1,2,2)+(1:8).
>>
>> Martin Maechler:
>> That is an interesting idea. Yes, in my view that would
>> definitely also have to allow the latter, by the above argument
>> of not treating the dim/dimnames attributes special. For
>> nonarrays length1 is not treated much special apart from the
>> fact that length1 can always be recycled (without warning).
> I think one could argue for allowing matrix(1,1,1)+(1:8) but not
> matrix(1,2,2)+(1:8). Length1 vectors certainly are special in some
> circumstances, being R's only way of representing a scalar. For
> instance, if (c(T,F)) gives a warning.
well, the if(.) situation is very special and does not weigh
much for me, here.
> This really goes back to what I think may have been a basic mistake in
> the design of S, in deciding that everything is a vector, then halfway
> modifying this with dim attributes, but it's too late to totally undo
> that (though allowing a 0length dim attribute to explicitly mark a
> length1 vector as a scalar might help).
(yes; I think there are also other ideas of adding true small
scalars to R... I am not familiar with those, and in any case
that should be a completely different thread and not be
discussed in this one)
>> > And I think there would be some significant problems. In addition to
>> > the 1020+ packages that Martin expects to break, there could be quite
>> > a bit of user code that would no longer work  scripts for analysing
>> > data sets that used to work, but now don't with the latest version.
>>
>> That's not true (at least for the cases above): They would give
>> a strong warning
> But isn't the intent to make it an error later? So I assume we're
> debating making it an error, not just a warning.
Yes, that's correct.
But if we have a longish deprecation period (i.e. where there's
only a warning) all important code should have been adapted
before it turns to an error
(( unless for those people who are careless enough to "graciously"
use something like suppressWarnings(...) in too many places )).
> (Though I'm
> generally opposed to such warnings anyway, unless they could somehow
> be restricted to come up only for interactive uses, not from deep in a
> program the user didn't write, making them totally mysterious...)
>> *and* the logic and relop versions of this, e.g.,
>> matrix(TRUE,1)  c(TRUE,FALSE) ; matrix(1,1) > 1:2,
>> have always been an error; so nothing would break there.
> Yes, that wouldn't change the behaviour of old code, but if we're
> aiming for consistency, it might make sense to get rid of that error,
> allowing code like sum(a%*%b<c(10,20,30)) with a and b being vectors,
> rather than forcing the programmer to write sum(c(a%*%b)<c(10,20,30)).
Yes, that would be another way for consistency... leading to
less problems in existing code. As said earlier, getting
consistency by becoming "more lenient" instead of "more restrictive"
is a good option in my view.
We would however have this somewhat special length1array
exception in how arrays behave in binary OPs, and both the underlying C
code and the full documentation being/becoming slightly more complicated
rather than simpler,
OTOH we would remain back compatible (*) to S or at least Splus
(as far as I know) and all earlier versions of R, here,
and that is valuable, too, I agree.
Nobody else has commented yet on this subthread ... not even
privately to me. If that status does not change quite a bit,
I don't see enough incentive for changing (the current Rdevel code).
Martin

(*) "backcompatible" in the sense that old code which "worked"
would continue to work the same
(but some old code that gave an error would no longer do so)
>> Of course; that *was* the reason the very special treatment for arithmetic
>> length1 arrays had been introduced. It is convenient.
>>
>> However, *some* of the conveniences in S (and hence R) functions
>> have been dangerous {and much more used, hence close to
>> impossible to abolish, e.g., sample(x) when x is numeric of length 1,
> There's a difference between these two. Giving an error when using a
> 1x1 matrix as a scalar may detect some programming bugs, but not
> giving an error doesn't introduce a bug. Whereas sample(2:n) behaving
> differently when n is 2 than when n is greater than 2 is itself a bug,
> that the programmer has to consciously avoid by being aware of the quirk.
> Radford Neal
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel


> > But isn't the intent to make it an error later? So I assume we're
> > debating making it an error, not just a warning.
>
> Yes, that's correct.
> But if we have a longish deprecation period (i.e. where there's
> only a warning) all important code should have been adapted
> before it turns to an error
That might be true for continuouslyused code. But for old scripts
for analysing some dataset that someone decides to run again five
years from now, they will be reduced to trying to guess which version
of R they ran under originally, or if they now want to use newer
features, to doing a binary search for the most recent version of R
for which they still work, or of course going through the script
trying to find the problem.
This wouldn't be a disaster, but I'm not seeing the magnitude of
benefit that would justify imposing this burden on users. A language
specification shouldn't really be changing all the time for no
particular reason.
Radford Neal
______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/rdevel

12
