Good question for @winston?
In the meantime I'll try an answer. Reactive expressions are implemented as R6 objects underneath, and reactive()
really just returns a method on this R6 object. When you transplant this method to a new R6 class, the method receives a new enclosing environment and can no longer access its original object. This explains why:
Implementation note: The external face of an R6 object is basically an environment with the public members in it. This is also known as the public environment. An R6 object’s methods have a separate enclosing environment which, roughly speaking, is the environment they “run in”. This is where self binding is found, and it is simply a reference back to public environment.
https://cran.r-project.org/web/packages/R6/vignettes/Introduction.html#basics
A simplified example might help.
ClassA <- R6::R6Class(
"ClassA",
portable = FALSE,
public = list(
x = 1,
test = function() {
x
}
)
)
a <- ClassA$new()
environment(a$test)
#> <ClassA>
#> Public:
#> clone: function (deep = FALSE)
#> self: ClassA, R6
#> test: function ()
#> x: 1
a$test()
#> [1] 1
# "transplant" a$test to a new R6 class
Test <- R6::R6Class(
"Test",
public = list(
test = a$test
)
)
t <- Test$new()
# the transplanted a$test runs in a different environment
# (the enclosing environment of the new object), and can no longer access
# fields on the original object
environment(t$test)
#> <environment: 0x0000000016d8a7a8>
identical(environment(t$test), t$.__enclos_env__)
#> [1] TRUE
t$test()
#> Error in t$test() : object 'x' not found
One way around this is to set the field in the initialize
method instead, which is probably what you want to do with reference objects anyway.
https://cran.r-project.org/web/packages/R6/vignettes/Introduction.html#fields-containing-reference-objects
Test <- R6Class(
classname = "Test",
public = list(
test = NULL,
initialize = function() {
self$test <- reactive({
2
})
}
)
)
isolate(Test$new()$test())
#> [1] 2