Skip to content

[<-.POSIXlt changes order of attributes (PR#9197)

6 messages · Brian Ripley, Gregor Gorjanc

#
This is a multi-part message in MIME format.
--------------090203020600020104020707
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit

Hello!

I was doing some tests with identical() and found out that [<-.POSIXlt
method changes order of attributes. This example shows that:

x <- strptime("1900-1-1", format="%Y-%m-%d")
x <- c(x)
y <- c(x, x+1)
x1 <- x
y1 <- y

attributes(x)
$names
[1] "sec"   "min"   "hour"  "mday"  "mon"   "year"  "wday"  "yday"  "isdst"

$class
[1] "POSIXt"  "POSIXlt"

$tzone
[1] ""     "CET"  "CEST"

identical(attributes(x), attributes(y))
TRUE

x[1] <- NA
attributes(x)
$names
[1] "sec"   "min"   "hour"  "mday"  "mon"   "year"  "wday"  "yday"  "isdst"

$tzone
[1] ""     "CET"  "CEST"

$class
[1] "POSIXt"  "POSIXlt"

y[1] <- NA
attributes(y)
$names
[1] "sec"   "min"   "hour"  "mday"  "mon"   "year"  "wday"  "yday"  "isdst"

$tzone
[1] ""     "CET"  "CEST"

$class
[1] "POSIXt"  "POSIXlt"

identical(attributes(x), attributes(x1))
FALSE

identical(attributes(y), attributes(y1))
FALSE

This can be solved with either:

Index: R/src/library/base/R/datetime.R
===================================================================
--- R/src/library/base/R/datetime.R     (revision 39045)
+++ R/src/library/base/R/datetime.R     (working copy)
@@ -713,10 +713,10 @@
 {
     if(!as.logical(length(value))) return(x)
     value <- as.POSIXlt(value)
-    cl <- oldClass(x)
+    att <- attributes(x)
     class(x) <- class(value) <- NULL
     for(n in names(x)) x[[n]][i] <- value[[n]]
-    class(x) <- cl
+    attributes(x) <- att
     x
 }

or in the same way as it is done in [.<-POSIXct method

Index: R/src/library/base/R/datetime.R
===================================================================
--- R/src/library/base/R/datetime.R     (revision 39045)
+++ R/src/library/base/R/datetime.R     (working copy)
@@ -714,9 +714,11 @@
     if(!as.logical(length(value))) return(x)
     value <- as.POSIXlt(value)
     cl <- oldClass(x)
+    tz <- attr(x, "tzone")
     class(x) <- class(value) <- NULL
     for(n in names(x)) x[[n]][i] <- value[[n]]
     class(x) <- cl
+    attr(x, "tzone") <- tz
     x
 }

I have checked both versions in r-devel with make check-all and all went
fine.

Regards, Gregor
#
Please point us to the documentation that says attributes are ordered.
E.g. R-lang.texi says

  All objects except @code{NULL} can have one or more attributes attached
  to them.  Attributes are stored as a list where all elements are named.

(although in fact they are stored in a pairlist).

I know of tens of functions that change the order of attributes, and 
did look at teaching identical() that they are not ordered.  But 
since they are stored as a pairlist, it would be quite expensive.
(Given that attributes seem to be growing in use, another internal storage 
mechanism is becoming more appropriate.)

BTW, all.equal() does not assume attributes are ordered.
On Fri, 1 Sep 2006, gregor.gorjanc at bfro.uni-lj.si wrote:

            

  
    
1 day later
#
There is a bug in identical(), though:
[1] TRUE
[1] TRUE

so identical() is not even looking at the names of the attributes but only 
checking their values.  Oops ....
On Fri, 1 Sep 2006, Prof Brian Ripley wrote:

            

  
    
#
Hello,
Prof Brian Ripley wrote:
I agree that there is no need for attributes to be always in the same
order as this is tedious to achieve as you noted above, but identical()
seems to care about this.
Which internal storage mechanism are you talking about here?

  
    
#
Hello,
Prof Brian Ripley wrote:
Aha, so this is the problem then. Thank you for tracking down the problem!
#
On Sat, 2 Sep 2006, Gregor Gorjanc wrote:

            
The one mentioned at

	'Attributes are stored as a list'

(but in fact a pairlist). We may want to change to e.g. a hash table.