On Fri, Jul 9, 2010 at 5:25 AM, Peter Dalgaard <pda...@gmail.com> wrote: > Gabor Grothendieck wrote: >> On Fri, Jul 9, 2010 at 5:09 AM, Peter Dalgaard <pda...@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 -Deepayan ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel