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

Cannot add functions to R6 that was declared without any public functions #51

Closed
daattali opened this issue Mar 23, 2015 · 2 comments
Closed

Comments

@daattali
Copy link

If I declare an R6 object and try to add a public function later, I get an error

Test <- R6::R6Class(
  "test",

  public = list(
  ),

  private = list(
  )
)

> Test$set("public", "setName", function(s) s)
Error in self[[group]][[name]] <- value : 
  invalid type/length (closure/0) in vector allocation

I seem to have to have at least one public function in the object definition to be able to do this without error

Test <- R6::R6Class(
  "test",

  public = list(
    anything = function(){}
  ),

  private = list(
  )
)

> Test$set("public", "setName", function(s) s)
@daattali
Copy link
Author

Same behaviour for private functions - you have to have at least one defined in order to add any later

@Tutuchan
Copy link

Tutuchan commented Apr 1, 2015

I noticed the same thing about a month ago, see here.

If you take a look at the source code, in r6_class.R, the public and private fields and methods are initialized this way :

 generator$public_fields   <- get_nonfunctions(public)
 generator$private_fields  <- get_nonfunctions(private)
 generator$public_methods  <- get_functions(public)
 generator$private_methods <- get_functions(private)

where get_functions is declared in utils.R in this way :

get_functions <- function(x) {
    funcs <- vapply(x, is.function, logical(1))
    if (all(!funcs)) return(NULL)
    x[funcs]
  }

So, if there are no functions in public, which is a list, get_functions will return NULL which means the public_methods field of the class will not exist. Then you try to set a new method on this class, take a look at the set code (I'm just pasting the interesting parts) :

generator_funs$set <- function(which = NULL, name = NULL, value, overwrite = FALSE) {
  (...)
  # Find which group this object should go in.
  if (which == "public") {
    group <- if (is.function(value)) "public_methods" else "public_fields"
  } else if (which == "private") {
    group <- if (is.function(value)) "private_methods" else "private_fields"
  } else if (which == "active") {
    if (is.function(value))
      group <- "active"
    else
      stop("Can't add non-function to active")
  }
  (...)
  # Assign in correct group
  self[[group]][[name]] <- value
  (...)
}

In the last line, you'll see that it tries to add the new value to a group that may not actually exist. So I guess for now, you'll have to add at least an element to each group that you think you may need later on. A possible fix would be to have get_functions and get_nonfunctions return an empty list rather than NULL when there are no elements.

@wch wch closed this as completed in 6882f91 Jun 22, 2015
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