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