Re: [Rd] Strange R object

From: Simon Urbanek <simon.urbanek_at_r-project.org>
Date: Fri, 09 Jul 2010 13:02:40 -0400

On Jul 9, 2010, at 12:41 PM, Deepayan Sarkar wrote:

> On Fri, Jul 9, 2010 at 5:25 AM, Peter Dalgaard <pdalgd_at_gmail.com> wrote:
>> Gabor Grothendieck wrote:
>>> On Fri, Jul 9, 2010 at 5:09 AM, Peter Dalgaard <pdalgd_at_gmail.com> wrote:

>>>> Gabor Grothendieck wrote:
>>>>> I have *** attached *** an RData file containing an R object that
>>>>> is acting strangely.
>>>>> 
>>>>> Try this in a fresh workspace. Do not load zoo or any other package.
>>>>> We load the object, zz2, from the attached RData file.  It is just
>>>>> the number 1 with the class c("zooreg", "zoo").
>>>>> 
>>>>> Now create an S3 print routine that simply prints an X when given
>>>>> an object of class "zoo".
>>>>> 
>>>>> If we use print on the object it produces an X but not if we just
>>>>> enter it at the console.  Also the object is not identical to its
>>>>> dput output.
>>>>> 
>>>>> How can such an object exist?  What is it about the object that is
>>>>> different from structure(1, class = c("zoo", "zooreg")) ?
>>>>> 

>>>> There's a bit in the SEXP structure that is supposed to be turned on
>>>> when an object has an S3 class. This is where implicit print looks,
>>>> whereas explicit print looks, er, elsewhere. Notice that
>>>>
>>>>> is.object(zz2)

>>>> [1] FALSE
>>>>> class(zz2) <- class(zz2)
>>>>> zz2

>>>> X
>>>>> is.object(zz2)

>>>> [1] TRUE
>>>>
>>>> Whenever the same information is stored in two ways, there is a risk of
>>>> inconsistency, so it is not too strange that you can have an ill-formed
>>>> .Rdata file (if you save zz2 back out, after the above fixup, line 11
>>>> changes from 526 to 782, corresponding to the bit being turned on).
>>>>
>>>> I don't think it is the job of load() to verify object structures, since
>>>> there is no end to that task. Rather, we shouldn't create them in the
>>>> first place, but you give us no clues as to how that object got made.
>>>>
>>> 
>>> This was originally a large object in a program that uses a variety of
>>> packages and it took quite a long time just to narrow it down to the
>>> point where I had an object sufficiently small to post.  Its not even
>>> clear at what point the object goes bad but your class(x) <- class(x)
>>> trick helped a lot and I have now been able to recreate it in a simple
>>> manner.
>>> 
>>> Below we create a new S3 class "X" with an Ops.X and print.X method.
>>> We then create an object x of that class which is just 1 with a class
>>> of "X".  When we multiply 1*x we get the bad object.  1*x and x have
>>> the same dput output but compare as FALSE.  1*x is not printed by
>>> print.X even though it is of class "X" while x is printed by print.X .
>>>  If we assign 1*x to xx and use your class assignment trick (class(xx)
>>> <- class(xx)) then xx prints as expected even though it did not prior
>>> to the class assignment.
>>> 

>>>> Ops.X <- function(e1, e2) { print("Ops.X"); NextMethod(.Generic) }
>>>> print.X <- function(x, ...) print("print.X")
>>>> x <- structure(1, class = "X")
>>>> dput(x)
>>> structure(1, class = "X")

>>>> dput(1*x)
>>> [1] "Ops.X"
>>> structure(1, class = "X")

>>>> identical(x, 1*x)
>>> [1] "Ops.X"
>>> [1] FALSE

>>>> 1*x
>>> [1] "Ops.X"
>>> [1] 1
>>> attr(,"class")
>>> [1] "X"

>>>> x
>>> [1] "print.X"

>>>> xx <- 1*x
>>> [1] "Ops.X"

>>>> class(xx) <- class(xx)
>>>> xx
>>> [1] "print.X"
>> 
>> Or, to minimize it further:
>> 
>>> x <- structure(1, class="y")
>>> is.object(x)
>> [1] TRUE
>>> is.object(x*1)
>> [1] TRUE
>>> is.object(1*x)
>> [1] FALSE
>>> class(x*1)
>> [1] "y"
>>> class(1*x)
>> [1] "y"
>> 
>> Yup, that looks like a bug.
> 
> I recently came across the following surprising behaviour which turns
> out to be the same issue. I had been meaning to ask for an
> explanation.
> 
>> x <- 1:20
>> class(x)
> [1] "integer"
>> is.object(x)
> [1] FALSE
>> print.integer <- function(x) print(x %% 5)
>> print(x)
> [1] 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0
>> x
> [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
> 


... that is an entirely different issue. x is still not an object because it doesn't have any explicit S3 class so it has nothing in common with the case discussed. This is about P in REPL which uses PrintValueEnv which is turn dispatches to print() only for objects (see main and print).

Cheers,
Simon



R-devel_at_r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel Received on Fri 09 Jul 2010 - 17:05:03 GMT

Archive maintained by Robert King, hosted by the discipline of statistics at the University of Newcastle, Australia.
Archive generated by hypermail 2.2.0, at Fri 09 Jul 2010 - 20:00:13 GMT.

Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel. Please read the posting guide before posting to the list.

list of date sections of archive