Let's say I define an S4 class 'foo'
with two slots 'a'
and 'b'
, and define an object x
of class 'foo'
,
setClass(Class = 'foo', slots = c(
a = 'numeric',
b = 'character'
))
x <- new('foo', a = rnorm(1e3L), b = rep('A', times = 1e3L))
format(object.size(x), units = 'auto') # "16.5 Kb"
Then I want to remove slot 'a'
from the definition of 'foo'
setClass(Class = 'foo', slots = c(
b = 'character'
))
slotNames(x) # slot 'a' automatically removed!! wow!!!
I see that R automatically take cares my object x
and have the slot 'a'
removed. Nice! But wait, the size of object x
is not reduced.
format(object.size(x), units = 'auto') # still "16.5 Kb"
format(object.size(new(Class = 'foo', x)), units = 'auto') # still "16.5 Kb"
Right.. Somehow 'a'
is still there but I just cannot do anything to it
head(x@a) # `'a'` is still there
rm(x@a) # error
x@a <- NULL # error
So question: how can I really remove slot 'a'
from x
and have its size reduced (which is my primary concern)?
My deepest gratitude to all answers!
The following solution is inspired by dww
trimS4slot <- function(x) {
nm0 <- names(attributes(x))
nm1 <- names(getClassDef(class(x))@slots) # ?methods::.slotNames
if (any(id <- is.na(match(nm0, table = c(nm1, 'class'))))) attributes(x)[nm0[id]] <- NULL # ?base::setdiff
return(x)
}
format(object.size(y1 <- trimS4slot(x)), units = 'auto') # "8.5 Kb"
The following solution is inspired by Robert Hijmans
setClass('foo1', contains = 'foo')
format(object.size(y2 <- as(x, 'foo1')), units = 'auto') # "8.5 Kb"
method::as
probably does some comprehensive checks, so it's quite slow though
library(microbenchmark)
microbenchmark(trimS4slot(x), as(x, 'foo1')) # ?methods::as 10 times slower
as
takes 79 microseconds (about 12,500 runs per second) --- how is that "quite slow"? The other method is faster, but is saving 70 microseconds relevant to you? If it does, then perhaps use the fastest (by a small margin) and cleanest solution:x@b <- ""
– Consensual