Behavior of saveRDS() and readRDS() in regard to objects' attributes

Aleksandr Blekh picture Aleksandr Blekh · May 18, 2014 · Viewed 12.9k times · Source

Do saveRDS and readRDS, correspondingly, save and restore all object's attributes, including ones created by an application (via attr)? I tried to use this approach instead of save and load, in an attempt to find a workaround for my problem linked below. However, it doesn't seem to be the case, unless I'm doing something wrong: Can I access R data objects' attributes without fully loading objects from file?.

Answer

gagolews picture gagolews · May 18, 2014

Yes, they do:

test <- structure(1:10, names=LETTERS[1:10], color='red', xxx='yyy')
attr(test, which='uuu') <- 'zzz'
test
##  A  B  C  D  E  F  G  H  I  J 
##  1  2  3  4  5  6  7  8  9 10 
## attr(,"color")
## [1] "red"
## attr(,"xxx")
## [1] "yyy"
## attr(,"uuu")
## [1] "zzz"
saveRDS(test, '/tmp/test.rds')
test2 <- readRDS('/tmp/test.rds')
identical(test, test2)
## [1] TRUE

R relies heavily on these functions (as well as their variants). For example, they are used to save the user's workspace. Thus, it would be odd if they hadn't stored the attributes.

However, do note that you cannot store some "dynamically created" objects with these. This includes file and SQL db connections handlers, temporary SQL result handlers, etc. An example with RCpp compiled functions:

library('Rcpp')
library('inline')   
cppFunction("int one() { return 1; }")
one() # it works
## [1] 1
one # contains a pointer to dynamically allocated mem chunk
## function () 
## .Primitive(".Call")(<pointer: 0x7f52c33a7680>)
saveRDS(one, '/tmp/one.rds')

Now we restart R...

one <- readRDS('/tmp/one.rds')
one # the pointer is no longer valid
## function () 
## .Primitive(".Call")(<pointer: (nil)>)
one() # doesn't work
## Error in .Primitive(".Call")(<pointer: (nil)>) : 
##  NULL value passed as symbol address