Does R copy unpaid slots in S4 classes when assigned?

Suppose I have an S4 class with two slots. Then I create a method that sets one of the slots to something and returns the result. Will another slot also be copied at assignment?

For instance,

setClass('foo', representation(first.slot = 'numeric', second.slot = 'numeric'))
setGeneric('setFirstSlot', function(object, value) {standardGeneric('setFirstSlot')})
setMethod('setFirstSlot', signature('foo', 'numeric'), function(object, value) {
 object@first.slot = value
 return(object)
 }) 

 f <- new('foo')
 f@second.slot <- 2
 f <- setFirstSlot(f, 1)

Will the values โ€‹โ€‹of the first and second slots be copied in the last line, or will there be some optimization? I have a class with a field containing a gigabyte of data and several fields with small numerical vectors, I would like to have a setter function for numerical fields that do not waste time unnecessarily copying data every time they are used.

Thank:)

+4
source share
2 answers

, . S4.

## Store timing output
m = matrix(0, ncol=4, nrow=6)

:

foo_ref = setRefClass("test", fields = list(x = "numeric", y = "numeric"))

:

## Reference class
g = function(x) {x$x[1] = 1; return(x)}
for(i in 6:8){
  f = foo_ref$new(x = 1, y = 1)
  y = runif(10^i)
  t1 = system.time({f$y <- y})[3]
  t2 = system.time({f$y[1] = 1})[3]
  t3 = system.time({f$x = 1})[3]
  t4 = system.time({g(f)})[3]
  m[i-5, ] = c(t1, t2, t3, t4)
}

S4:

g = function(x) {x@y[1] = 1; return(x)}
setClass('foo_s4', representation(x = 'numeric', y = 'numeric'))
for(i in 6:8){
  f = new('foo_s4'); f@x = 1; f@y = 1
  y = runif(10^i)
  t1 = system.time({f@y <- y})[3]
  t2 = system.time({f@y[1] <- 1})[3]
  t3 = system.time({f@x = 1})[3]
  t4 = system.time({g(f)})[3]
  m[i-2, ] = c(t1, t2, t3, t4)
}

.

enter image description here

  • 3.1
  • R < 3.1, t3 S4 .
+3

( ), @<- setter setFirstSlot, , . , .

, , , . , @<- x ( numeric), .

setClass('foo', representation(x = 'numeric', y = 'numeric'))
f <- new('foo')
f@x <- 1 # this is ok
f@y <- 2 # this is ok
f@x <- "a"
#Error in checkAtAssignment("foo", "x", "character") : 
#  assignment of an object of class "character" is not valid for @โ€˜xโ€™ in an object of class "foo"; is(value, "numeric") is not TRUE

, . @<-:

# this assignment is allowed
f@x <- c(1, 2, 3, 4)
f@x
#[1] 1 2 3 4

setter, . , , .

, . setValidity , , @<- validObject, f@x <- c(1, 2, 3, 4) , setValidity

valid.foo <- function(object)
{
  if (length(object@x) > 1)
    stop("slot ", sQuote("x"), " must be of length 1")
}
setValidity("foo", valid.foo)
# no error is detected and the assignment is allowed
f@x <- c(1, 4, 6)
f@x
#[1] 1 4 6
# we need to call "validObject" to check if everything is correct
validObject(f)
#Error in validityMethod(object) : slot โ€˜xโ€™ must be of length 1

. set.x.inplace .

setGeneric("set.x.inplace", function(object, val){ standardGeneric("set.x.inplace") })
setMethod("set.x.inplace", "foo", function(object, val)
{
  if (length(val) == 1) {
    eval(eval(substitute(expression(object@x <<- val))))
  } else
    stop("slot ", sQuote("x"), " must be of length 1")
  #return(object) # not necessary
})

set.x.inplace(f, 6)
f
#An object of class "foo"
#Slot "x":
#[1] 6
#Slot "y":
#[1] 2

# the assignment is not allowed
set.x.inplace(f, c(1,2,3))
#Error in set.x.inplace(f, c(1, 2, 3)) : slot โ€˜xโ€™ must be of length 1

, .

+3

Source: https://habr.com/ru/post/1532084/


All Articles