[Rd] (PR#13209) Arith ops dropping S4 *and* 'object' bit [Was: ...]
maechler at stat.math.ethz.ch
maechler at stat.math.ethz.ch
Thu Oct 30 12:20:13 CET 2008
>>>>> "JMC" == John Chambers <jmc at r-project.org>
>>>>> on Tue, 28 Oct 2008 11:50:38 -0400 writes:
JMC> The asymmetry is just the symptom of a more fundamental
JMC> issue: There are no operator methods currently defined
JMC> for "vector" classes, either combined with each other
JMC> or with a non-S4 object.
JMC> The consequence is that computations drop through to
JMC> the primitive C code. Not a good idea, because that
JMC> code does various things to objects with attributes,
JMC> some of them bizarre and most of them not what should
JMC> logically happen for S4 classes.
JMC> Consider two classes with slightly more content than "test":
>> setClass("test1",contains = "vector", representation(label= "character"))
JMC> [1] "test1"
>> setClass("test2",contains = "vector", representation(flag = "logical"))
JMC> [1] "test2"
JMC> These two classes both inherit from "vector" but are unrelated to each
JMC> other.
JMC> What should happen for arithmetic and other operators
JMC> combining these two classes? There's some scope for
JMC> discussion, but a reasonable policy is that the vector
JMC> parts should be used and a result returned that is a
JMC> simple vector. What should NOT happen is that one class
JMC> is retained and the other thrown away--that's not a
JMC> meaningful interpretation of the two definitions
JMC> here. Unfortunately, that's what does happen with the
JMC> primitives. Example below.
JMC> We need to develop some methods for combinations of "vector" and "ANY"
JMC> reflecting what's sensible. I'll put some first attempts on r-devel and
JMC> we can discuss what's wanted. (May not happen right away, but hopefully
JMC> in a week or two.)
That sounds very good !
Note that there's a related infelicity of primitives dealing
with class-attributes that does *not* involve S4 at all.
I'm adding an extra test to str() {i.e. str.default} in order to
get rid of the infinite recursion in the following,
but we might also consider to change the behavior of '+' here :
## str() with an "invalid object"
ob <- structure(1, class = "test") # this is fine
is.object(ob)# TRUE
ob <- 1 + ob # << this is "broken"
is.object(ob)# FALSE - hmm, ....
identical(ob, unclass(ob)) # TRUE (!!!!) and as a consequence :
str(ob)
## infinite recursion in R <= 2.8.0
--
Martin Maechler, ETH Zurich
JMC> ---------------------
JMC> Example:
JMC> If the objects are equal in length, the left operand wins, or seems to:
>> x1 = new("test1", 1:10, label = "Something")
>> x2 = new("test2", 10:1, flag = rep(TRUE, 10))
>> x1+x2
JMC> An object of class âtest1â
JMC> [1] 11 11 11 11 11 11 11 11 11 11
JMC> Slot "label":
JMC> [1] "Something"
>> x2+x1
JMC> An object of class âtest2â
JMC> [1] 11 11 11 11 11 11 11 11 11 11
JMC> Slot "flag":
JMC> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
JMC> But in fact, it's weirder than that, because _all_ the attributes are
JMC> retained:
>> names(attributes(x1+x2))
JMC> [1] "flag" "class" "label"
>> names(attributes(x2+x1))
JMC> [1] "label" "class" "flag"
JMC> That was with equal lengths. Otherwise, the code uses the longer
JMC> object's attributes, including the class.
>> x11 = new("test1", 101:105,label = "Smaller")
>> x11 +x2
JMC> An object of class âtest2â
JMC> [1] 111 111 111 111 111 106 106 106 106 106
JMC> Slot "flag":
JMC> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
>> x2+x11
JMC> An object of class âtest2â
JMC> [1] 111 111 111 111 111 106 106 106 106 106
JMC> Slot "flag":
JMC> [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
>> names(attributes(x11+x2))
JMC> [1] "flag" "class"
JMC> Simon Urbanek wrote:
>>
>> On Oct 27, 2008, at 12:25 , Robert.McGehee at geodecapital.com wrote:
>>
>>> Hello all,
>>> It appears that for the simplest of S4 objects, z+1 does not equal 1+z.
>>> Presumably this is a bug, as 1+z seems to make a malformed object (at
>>> least malformed as an input to str).
>>
>> FWIW the difference is that z+1 has the S4 bit set, 1+z does not. The
>> objects are otherwise identical. AFAICS the same behavior is
>> reproducible with any binary arithmetic operator (i.e. non-S4 %op% S4
>> will produce a result with S4 bit cleared yet valid S4 attributes).
>>
>> Cheers,
>> S
>>
>>
>>
>>>
>>>> setClass("test", representation("vector"))
>>> [1] "test"
>>>> z <- new("test", 1)
>>>> identical(z+1, 1+z)
>>> [1] FALSE
>>>> str(z+1)
>>> Formal class 'test' [package ".GlobalEnv"] with 1 slots
>>> ..@ .Data: num 2
>>>> str(1+z)
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class
>>> 'test' Class 'test' Class 'test' Class 'test' Class 'test' Class 'test'
>>> Class 'test' Class 'test' Error: evaluation nested too deeply: infinite
>>> recursion / options(expressions=3D)?
>>>
>>>> R.version
>>> _ =20
>>> platform x86_64-unknown-linux-gnu =20
>>> arch x86_64 =20
>>> os linux-gnu =20
>>> system x86_64, linux-gnu =20
>>> status =20
>>> major 2 =20
>>> minor 8.0 =20
>>> year 2008 =20
>>> month 10 =20
>>> day 20 =20
>>> svn rev 46754 =20
>>> language R =20
>>> version.string R version 2.8.0 (2008-10-20)
>>>
>>> ______________________________________________
>>> R-devel at r-project.org mailing list
>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>
>>>
>>
>> ______________________________________________
>> R-devel at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>
JMC> ______________________________________________
JMC> R-devel at r-project.org mailing list
JMC> https://stat.ethz.ch/mailman/listinfo/r-devel
More information about the R-devel
mailing list