I am getting the error argument "..1" is missing, with no default when I load an R6 object from disk, and trying to call setDT or as.data.table on an R6 field containing a data.table object. A simple R6 object doesn't throw this error (see the related question: Loading R6 objects that have data.table fields), but I am at my wits' end trying to find this error in my code.
Perplexity AI seems to suggest it has to do with ellipsis ..., but then proceeds to hallucinate code to "reproduce" the error.
Can someone please explain:
..1 the error refers to?R6 and/or data.table code?There are two parts to this answer, the first and main one is that it is possible to construct an active binding (a member of the R6 object, and not a field as erroneously referred to in my original post), that only retrieves the value corresponding to a private field. The function setDT fails as somehow it involves/invokes a call to <- when the object is loaded from disk.
A reproducible example is:
# convenience function to define active bindings
# see https://stackoverflow.com/questions/79719481/how-to-use-a-closure-to-make-an-assignment-active-binding-in-r6
active_col_creator_retrieve_only <- function(private_field, error_message = "Retrieve only.") {
eval(substitute(function(value) {
if (missing(value)) {
private[[paste0(".", private_field)]]
} else {
stop(error_message)
}
}
))
}
## example R6 class
testR6_arc_we <- R6Class("testR6",
public = list(initialize = function(test_) {
private$.test <- test_
}),
private = list(.test = data.table()),
active = list(test = active_col_creator_retrieve_only("test")
)
)
## create example data
test <- data.table(id = letters[1:2], val=1:2)
test_R6_arc_we <- testR6_arc_we$new(test)
saveRDS(test_R6_arc_we, "data_20251008_test_R6_arc_we.rds")
test_R6_arc_we_3 <- readRDS("data_20251008_test_R6_arc_we.rds")
And we see that:
test_R6_arc_we_2 <- readRDS("data_20251008_test_R6_arc_we.rds")
all.equal(test_R6_arc_we, test_R6_arc_we_2)
#[1] TRUE
# but comparing the first call (no error) to the 2nd.
setDT(test_R6_arc_we$test)
setDT(test_R6_arc_we_2$test)
# Error in (function (value) : Retrieve only.
The traceback is interesting and call "2." points to a section of the setDT code:
4.stop("Retrieve only.")
3.(function (value) { if (missing(value)) { private[[paste0(".", "test")]] ...
2.assign(as.character(name[[3L]]), x, k, inherits = FALSE)
1.setDT(test_R6_arc_we_2$test)
The solution is to have an method internal to the R6 object that can access and modify the private field. Unfortunately, none of setDT, or [, tmp_var := NULL] works, so for now I have to resort to copying the data.
testR6_arc_we_fixed <- R6Class("testR6",
public = list(initialize = function(test_) {
private$.test <- test_
},
reset_dt = function(dt_name = character(),
is_private = T) {
if (is_private) {
private[[dt_name]] <-
as.data.table(private[[dt_name]])
} else {
setDT(public[[dt_name]])
}
}),
private = list(.test = data.table()),
active = list(test = active_col_creator_retrieve_only("test")
)
)
For the second part of this answer, error argument "..1" is missing was caused by my own bug by not supplying a default (or any) argument to the error_message parameter in the convenience function. For completion, dropping the default argument value reproduces my original error:
active_col_creator_retrieve_only <- function(private_field, error_message) {
eval(substitute(function(value) {
if (missing(value)) {
private[[paste0(".", private_field)]]
} else {
stop(error_message)
}
}
))
}
testR6_arc <- R6Class("testR6",
public = list(initialize = function(test_) {
private$.test <- test_
}),
private = list(.test = data.table()),
active = list(test = active_col_creator_retrieve_only("test")
)
)
test <- data.table(id = letters[1:2], val=1:2)
test_R6_arc <- testR6_arc$new(test)
saveRDS(test_R6_arc, "data_20251008_test_R6_arc.rds")
test_R6_arc_2 <- readRDS("data_20251008_test_R6_arc.rds")
and
setDT(test_R6_arc_2$test)
# Error in stop() : argument "..1" is missing, with no default