My goal is to modify the behavior of the initialize method depending on the type of the argument. For example, if I call MyClass$new(list()) I'd like to initialize my object with a list, and if I call MyClass$new("foo") I'd like to initialize the object with a character string. I think S3 generics are very useful for that, so I did something like this:
initialize_test_class <- function(x) UseMethod("initialize_test_class")
initialize_test_class.default <- function(x) {
warning("don't know what to do")
}
initialize_test_class.list <- function(x) {
print("initialized with a list")
}
initialize_test_class.character <- function(x) {
print("initialized with a character")
}
TestClass <- R6::R6Class(
classname = "TestClass",
public = list(
initialize = function(x) {
initialize_test_class(x)
}
)
)
TestClass$new(list(a = 1))
TestClass$new("foo")
And it works, but I'm wondering maybe there's a more elegant way to do it? Some more general advices about OOP good practices in such cases are welcome, too.
If initialization of the R6 class is the sole purpose of your S3 class, I would say you are definitely over-engineering this. There are other methods for type-checking input that are simpler (and possibly safer) than relying on S3 dispatch. For example
is.list(x)andis.character(x)might be useful here, orinherits(x, 'list')andinherits(x, 'character').So I think a more elegant solution here would be:
Though depending on the complexity of your initialization methods, you may wish to bring the methods outside of the class definition, but don't have them as S3:
Both of which give the same result:
Created on 2023-09-21 with reprex v2.0.2