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

Proper way to implement S3 dispatch on R6 classes #42

Closed
daattali opened this issue Jan 27, 2015 · 1 comment
Closed

Proper way to implement S3 dispatch on R6 classes #42

daattali opened this issue Jan 27, 2015 · 1 comment

Comments

@daattali
Copy link

Crossposting from SO as I haven't received any answers there, I hope that's ok.

TL;DR: While it's not difficult to see how to implement S3 methods for R6 classes, I could not find examples in the documentation that officially show the proper way to do this. Also, I wanted to know if it is discouraged to implement S3 functions and instead the equivalent R6 functions should be encouraged to use? ie. does it matter if we do as.list(myR6) vs myR6$as.list()

Below is a copy-n-paste from the SO post:


I have an R6 class and I want to add an S3 method for it. The documentation I found mentioned briefly that in order to use S3 dispatch on R6 you must have class = TRUE, but I couldn't find an example of how it should be done.

I did see empirically that simply writing an S3 method in the form s3generic.r6class worked, but I wanted to know if that is indeed to right way to write an S3 method for R6.

For example, say I have an R6 class that enhances a list

library(R6)

R6list <- R6Class(
  "R6list",
  public = list(
    orig = NULL,
    initialize = function(x) {
      self$orig <- x
    }
  )
)

Question 1

Naturally, I want to provide a method for obtaining the underlying list, so I wanted to add an as.list method. Is it standard to add both an S3 generic AND a as.list public function inside the class? My intuitive answer is to add both.

R6list <- R6Class(
  "R6list",
  public = list(
    orig = NULL,
    initialize = function(x) {
      self$orig <- x
    },
    as.list = function() {
      self$orig
    }
  )
)

as.list.R6list <- function(x, ...) {
  x$as.list()
}

So that now if I have an object mylist <- R6list$new(as.list(letters[1:5])) I can either call as.list(mylist) or mylist$as.list(). Is one of those preferred over the other?

Question 2
Is there anything special about writing an S3 method for R6 classes, or is what I wrote above sufficient and the correct way? I wasn't sure if the S3 method has to be written outside of the class definition, or if R6 somehow provides a way to write S3 methods within it so that all the code relating to the class is localized.

@wch
Copy link
Member

wch commented Feb 5, 2015

Good questions.

Answer 1: There isn't a generally preferred way of calling it -- at least, not yet. If you're using an R6 object, you may prefer to call mylist$as.list(), just to be consistent with calling other methods on the object. On the other hand, you may prefer to call as.list(mylist) if you want to be consistent with other R objects. The latter may be appropriate especially if you're calling as.list() in a function, and the input could be many types, not just R6list.

Answer 2: You wrote it correctly. The S3 method is defined outside of the class.

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

2 participants