I want to create an R6 object that can accept only pre-defined fields. I can do this by defining get
and set
methods. However, to apply this to my existing code I'd like to extend syntax to replace get
with $
and set
with <-
. Since I know very little about R6, I asked ChatGPT, and got this answer:
state_container <- R6Class(
"state_container",
public = list(
initialize = function(fields) {
private$fields <- fields
private$values <- list()
},
get = function(field) {
if (!field %in% private$fields) {
stop(sprintf("Field '%s' is not a predefined field.", field))
}
private$values[[field]]
},
set = function(field, value) {
if (!field %in% private$fields) {
stop(sprintf("Field '%s' is not a predefined field.", field))
}
private$values[[field]] <- value
},
get_all = function() {
lapply(private$fields, function(field) private$values[[field]])
},
# Define method to support app_state$field syntax for getting
`$.get` = function(field) {
self$get(field)
},
# Define method to support app_state$field <- value syntax for setting
`$<-.set` = function(field, value) {
self$set(field, value)
}
),
private = list(
fields = NULL,
values = NULL
)
)
This seems to work well with set
and get
:
> state <- state_container$new(c("foo", "bar"))
> state$set("foo", "one")
> state$get("foo")
[1] "one"
> state$set("not_allowed", "two")
Error in state$set("not_allowed", "two") :
Field 'not_allowed' is not a predefined field.
> state$get("not_allowed")
Error in state$get("not_allowed") :
Field 'not_allowed' is not a predefined field.
However, the proposed syntax extension does not work:
> state$foo <- "one"
Error in state$foo <- "one" : cannot add bindings to a locked environment
> state$foo
NULL
> state$not_allowed
NULL
What I need is for state$foo <- "one"
to work and be aware of not predefined fields, and for state$foo
to return the correct value and for state$not_allowed
to throw an error.