Search code examples
rr-s4

Simultaneously updating object and returning value in S4 classes


I need to write one method that simultaneously updates an object and returns a value. I want to know if there is a way to do this in S4 classes. The context for this is that I am trying to write an S4 class to generate a list each element of which can be accessed only if a private key is known. To do this I need a method getNewSlot that simultaneously updates the length of the list and the key list and returns the index key pair. The code is provided below:

setClass("ProtectedRObjectList", 
  representation(objectList = "list", keys = "character", length = "numeric"))

setGeneric(
  name = "getNewSlot",
  def = function(object,value){standardGeneric("getNewSlot")})

setMethod(
  f = "getNewSlot", 
  signature = "ProtectedRObjectList", 
  definition = function(object){
    if(length(object@length)==0)
    {
      #initial case
      object@length <- 0;
    }

    #update list length and generate random key
    object@length<-object@length + 1;
    object@keys[object@length]<-paste(sample(c(letters, LETTERS), 15, replace =TRUE), collapse = "");
    #return "index, key" pair
    return(list("index" = object@length, "key" = object@keys[object@length]))
  }
)

Here is the output of this method. As you can see, the code returns the desired "index, key" pair, but doesn't update the object.

> thisObj<-new("ProtectedRObjectList")
> thisObj
An object of class "ProtectedRObjectList"
Slot "objectList":
list()

Slot "keys":
character(0)

Slot "length":
numeric(0)

> output<-getNewSlot(thisObj)
> output
$index
[1] 1

$key
[1] "cjdkDvAaNjvVKdw"

> thisObj
An object of class "ProtectedRObjectList"
Slot "objectList":
list()

Slot "keys":
character(0)

Slot "length":
numeric(0)

Solution

  • maybe this is not what you want, but probably R5 class is suitable for your purpose since you need pass-by-reference function call.

    it is easy to rewrite R5 class from S4 class (and implementation in R5 is easier than that in S4).
    Here is a definition (note that field length is replaced by len because of name duplication):

    ProtectedRObjectList <- setRefClass(
      "ProtectedRObjectList", 
      fields = list(objectList = "list", keys = "character", len = "numeric"),
      methods=list(
        getNewSlot = function(){
          if(length(len)==0)
          {
            #initial case
            len <<- 0;
          }
          #update list length and generate random key
          len<<-len + 1;
          keys[len]<<-paste(sample(c(letters, LETTERS), 15, replace =TRUE), collapse = "");
          #return "index, key" pair
          return(list("index" = len, "key" = keys[len]))
        }
      )
    )
    

    and usage:

    > thisObj<-ProtectedRObjectList$new()
    > thisObj
    An object of class "ProtectedRObjectList"
    <environment: 0x116207c30>
    > thisObj$len
    numeric(0)
    > thisObj$keys
    character(0)
    > 
    > output<-thisObj$getNewSlot()
    > output
    $index
    [1] 1
    
    $key
    [1] "GeCyCTdIflcYFbE"
    
    > 
    > thisObj$len
    [1] 1
    > thisObj$keys
    [1] "GeCyCTdIflcYFbE"