Bug 13209 - S4 object does not commute?
S4 object does not commute?
Status: RESOLVED WONTFIX
Product: R
Classification: Unclassified
Component: Low-level
old
All Linux
: P5 normal
Assigned To: R-core
: 13222 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2008-10-27 21:22 UTC by Jitterbug compatibility account
Modified: 2010-04-12 23:13 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jitterbug compatibility account 2008-10-27 21:22:17 UTC
From: "McGehee, Robert" <Robert.McGehee@geodecapital.com>
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).
Thanks, Robert


> 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=)?

> R.version
               _                           
platform       x86_64-unknown-linux-gnu    
arch           x86_64                      
os             linux-gnu                   
system         x86_64, linux-gnu           
status                                     
major          2                           
minor          8.0                         
year           2008                        
month          10                          
day            20                          
svn rev        46754                       
language       R                           
version.string R version 2.8.0 (2008-10-20)

Comment 1 Jitterbug compatibility account 2008-10-27 22:49:25 UTC
From: Simon Urbanek <simon.urbanek@r-project.org>

On Oct 27, 2008, at 12:25 , Robert.McGehee@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@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

Comment 2 Jitterbug compatibility account 2008-10-30 16:14:50 UTC
From: Martin Maechler <maechler@stat.math.ethz.ch>
>>>>> "JMC" == John Chambers <jmc@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@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@r-project.org mailing list
    >>> https://stat.ethz.ch/mailman/listinfo/r-devel
    >>> 
    >>> 
    >> 
    >> ______________________________________________
    >> R-devel@r-project.org mailing list
    >> https://stat.ethz.ch/mailman/listinfo/r-devel
    >> 

    JMC> ______________________________________________
    JMC> R-devel@r-project.org mailing list
    JMC> https://stat.ethz.ch/mailman/listinfo/r-devel

Comment 3 Jitterbug compatibility account 2008-11-03 16:05:28 UTC
Audit (from Jitterbug):
Mon Nov  3 10:05:28 2008	ripley	moved from incoming to Low-level
Comment 4 Brian Ripley 2010-04-12 11:32:07 UTC
still open see also 13222
but MM's red herring now works.
Comment 5 Brian Ripley 2010-04-12 11:32:28 UTC
*** Bug 13222 has been marked as a duplicate of this bug. ***
Comment 6 John Chambers 2010-04-12 23:13:01 UTC
The S4 bit should now (rev. 51702) be set if either operand is an S4 object.

However, this is not the solution to commutativity, the cause of which is obscure and unrelated to S4 objects, but seems to have to do with the class attribute.  For example:

> x = 1
> class(x) = "foo" ## which is not an S4 class
> isS4(x)
[1] FALSE
> identical(x+1, 1+x)
[1] FALSE
> all.equal(x+1, 1+x)
[1] TRUE
> 
> y = 1
> attr(y, "anything") = "set"
> identical(y+1, 1+y)
[1] TRUE

However, with this fix, at least 1+x is a valid object.