Reputation: 8025
I would like to use delayed assign to assign a new value to a slot of an S4 object. This assignment is basically a database query, and I only want the database query to be executed when the value is actually used.
But for the sake of testing this will do as well:
testFunction <- function(id = 1){
print("running query")
return(id)
}
delayedAssign("test", testFunction(id = 2))
This works. "running query" is only printed when test is called, not on assignment. In contrast to:
test2 <- testFunction(id = 2)
Now I would like to be able to do the same thing, but then on a slot.
delayedAssign("someObject@slotName", testFunction(id = 2))
This unfortunately creates an object names 'someObject@slotName' in the current environment. Any ideas on how to solve this?
Upvotes: 0
Views: 174
Reputation: 46856
This represents somewhat of a hack, with unpleasant implementation details. Here's an S4 class, with an environment as a slot
.B <- setClass("B", representation(b="environment"))
I pay attention to initialization, so each instance gets its own environment (rather than all instances sharing the same environment, which would be the default and appropriate if there were a singleton)
setMethod(initialize, "B",
function(.Object, ..., b=new.env(parent=emptyenv()))
{
b[["value"]] <- NA
callNextMethod(.Object, ..., b=b)
})
Let's define generics to set and retrieve the delay-assigned values
setGeneric("delay<-", function(x, ..., value) standardGeneric("delay<-"))
setGeneric("delay", function(x, ...) standardGeneric("delay"))
then implement the method to assign a value to an element, 'value', in our environment
setReplaceMethod("delay", "B", function(x, ..., value) {
force(value) # don't want to be _too_ lazy
delayedAssign("value", testFunction(value), assign.env=x@b)
x
})
and to retrieve it
setMethod("delay", "B", function(x, ...) x@b[["value"]])
Here's the product of our labor...
> b <- .B()
> delay(b)
[1] NA
> delay(b) <- 1 # no type safety; could use, e.g., delay<-,numeric-method
> delay(b)
[1] "running query"
[1] 1
with some weird reference semantics (because b1 and b share the same environment) that would surprise our user (probably even our user expecting reference semantics)
> b1 <- b # reference semantics, delayed
> delay(b1) <- 2
> delay(b)
[1] "running query"
[1] 2
Upvotes: 3