For an R package I am working on (which creates an S4 class), I would like to delay loading some data until the user actually asks for it (because it may or not be required and loading it takes a little while). This would require me to set a slot's value within its getter (aka accessor) method if it has not previously been loaded. But I cannot get the new value to "stick". Here is an MRE:
setClass("A", representation(value = "numeric"))
setGeneric("value<-", function(x, value) standardGeneric("value<-"))
setGeneric("value", function(x) standardGeneric("value"))
setMethod("value<-", signature("A", "numeric"),
function(x, value)
{
x@value = value
x
})
setMethod("value", signature(x = "A"),
function(x)
{
if(!length(x@value))
value(x) <- 20
x@value
})
This produces the following result:
> a <- new("A")
> value(a)
[1] 20
> a
An object of class "A"
Slot "value":
numeric(0)
So the value() function returns the desired new value (20), but this value is not actually updated in the object. Doing x@value <- value
instead of value(x) <- 20
in the getter did not succeed either.
It seems the problem is that I am not returning the updated object in my getter (the way my setter does), but I have something else to return in my getter (the value).
What is the Right Way To Do This™?
Thank you!
EDIT:
After futher study of S4 pass-by-value semantics, I have come to the conclusion that this is Simply Not Possible™. If a slot is updated, the object must be returned, and you can't return something else instead. Can someone confirm my conclusion is correct?
setRefClass
or the R6 package. S4 does not have traditional OOP mutability. – Alexis