Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for heritable classmethods #260

Open
alistaire47 opened this issue Jun 7, 2022 · 0 comments
Open

Support for heritable classmethods #260

alistaire47 opened this issue Jun 7, 2022 · 0 comments

Comments

@alistaire47
Copy link

In Python, classmethods are heritable methods that can be called from the class itself MyClass.class_method() (not just from an instance of that class MyClass().normal_method()) like a staticmethod, but which also has access to cls, the class definition. This is particularly helpful for alternate ways of instantiating a class, like pd.DataFrame.from_dict().

In R6, all methods are only available after instantiation, unless they're explicitly added to the environment after class creation like

MyClass <- R6Class(...)
MyClass$my_static_method <- function() ...

but that is effectively a non-heritable (it will not exist on any child classes) static method, not a class method that has access to the class itself. Since MyClass already exists, you could call it recursively:

MyClass$my_quasi_class_method <- function(...) do.call(MyClass$new, list(...))

...but that moves it further from heritability, since when inherited it would still point to the parent class instead of the current class.

For my own purposes (I needed a set of classes that can be serialized/deserialized to/from JSON), I created a wrapper around R6Class that stores classmethods (all in a static list for now, since any classmethod that does not reference self (really equivalent to cls here) is a staticmethod) in private$static, and then appends them to child classes when applicable:

R6Point1Class <- function(..., static = NULL) {
  Class <- R6::R6Class(...)
  Class$parent_env <- parent.frame()

  full_static <- modifyList(
    Class$get_inherit()$private_fields$static %||% list(),
    static %||% list()
  )
  full_static <- lapply(full_static, function(x) {
    if (!is.function(x)) return(x)
    environment(x) <- Class
    x
  })
  Class$set('private', 'static', full_static)

  for (name in names(Class$private_fields$static)) {
    Class[[name]] <- Class$private_fields$static[[name]]
  }

  Class
}

I'm sure this implementation has bugs and corner cases (at a minimum, it does not play nice with roxygen), but given that class methods are common in Python, maybe there is appetite for adding support directly to R6Class? #66 looks like a similar proposal for static attributes and methods; this would presumably be similarly implemented, but with an evaluation environment with access to the class definition (presumably as self or class or cls or some other reserved keyword). At a minimum, it seems to me worth a conversation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant