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

Comments

@daattali
Copy link

commented Mar 23, 2015

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

This comment has been minimized.

Copy link
Author

commented Mar 23, 2015

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

@Tutuchan

This comment has been minimized.

Copy link

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 in 6882f91 Jun 22, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.