The active binding tmp_priv_2
does not work as expected:
active_creator <- function(clmn) {
function(value) {
if (missing(value)) {
private[[paste0(".", clmn)]]
} else {
if (!is.na(private[[paste0(".", clmn)]]))
warning(paste0("Overriding existing tmp_replace: ",
private[[paste0(".", clmn)]]))
private[[paste0(".", clmn)]] <- value
}
}
}
tmpClass <-
R6Class("tmpClass",
private = list(.tmp_priv = NA_character_),
active = list(
tmp_priv = function(value) {
clmn <- "tmp_priv"
if (missing(value)) {
private[[paste0(".", clmn)]]
} else {
if (!is.na(private[[paste0(".", clmn)]]))
warning(paste0("Overriding existing tmp_replace: ",
private[[paste0(".", clmn)]]))
private[[paste0(".", clmn)]] <- value
}
},
tmp_priv_2 = active_creator("tmp_priv"))
)
TC <- tmpClass$new()
The following results are expected:
> TC$tmp_priv
[1] NA
> TC$tmp_priv <- "asdf"
> TC$tmp_priv <- "zxcv"
Warning message:
In (function (value) : Overriding existing tmp_replace: asdf
But the following returns an error instead of behaving like the tmp_priv
binding:
> TC$tmp_priv_2 <- "asdf"
Error in (function (value) : object 'clmn' not found
Yet:
> as.list(environment(tmpClass$active$tmp_priv_2))
$clmn
[1] "tmp_priv"
The idea of using one function to define all the active bindings is related to: Function for standard active binding in R6
EDIT (2025-07-30): After receiving the two very helpful answers, comments, and some debugging with Claude AI, I found this old github issue which discusses in great detail closures and R6 active bindings. In short, it is exactly as user2554330 describes.
clmn
exists in the function's environment, but it's not available when R6 calls the function. That said, the solution is the same as the linked question:
library(R6)
active_creator <- function(clmn) {
eval(substitute(function(value) {
if (missing(value)) {
private[[paste0(".", clmn)]]
} else {
if (!is.na(private[[paste0(".", clmn)]])) {
warning(paste0("Overriding existing tmp_replace: ",
private[[paste0(".", clmn)]]))
}
private[[paste0(".", clmn)]] <- value
}
}))
}
tmpClass <- R6Class("tmpClass",
private = list(.tmp_priv = NA_character_),
active = list(
tmp_priv = function(value) {
clmn <- "tmp_priv"
if (missing(value)) {
private[[paste0(".", clmn)]]
} else {
if (!is.na(private[[paste0(".", clmn)]]))
warning(paste0("Overriding existing tmp_replace: ",
private[[paste0(".", clmn)]]))
private[[paste0(".", clmn)]] <- value
}
},
tmp_priv_2 = active_creator("tmp_priv")
)
)
TC <- tmpClass$new()
TC$tmp_priv
#> [1] NA
TC$tmp_priv <- "asdf"
TC$tmp_priv <- "zxcv"
#> Warning in (function (value) : Overriding existing tmp_replace: asdf
TC$tmp_priv_2 <- "qwerty"
#> Warning in (function (value) : Overriding existing tmp_replace: zxcv
TC <- tmpClass$new()
TC$tmp_priv_2
#> [1] NA
TC$tmp_priv_2 <- "azerty"
TC$tmp_priv_2 <- "qwertz"
#> Warning in (function (value) : Overriding existing tmp_replace: azerty
TC$tmp_priv <- "zxcv"
#> Warning in (function (value) : Overriding existing tmp_replace: qwertz
Created on 2025-07-30 with reprex v2.1.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With