r-lib / R6

Encapsulated object-oriented programming for R
https://R6.r-lib.org
Other
405 stars 56 forks source link

Extending documentation on R6Class(... parent_env = parent.frame() ...) #90

Closed petermeissner closed 7 years ago

petermeissner commented 7 years ago

Gist:

This is _not a bug but merly the request to add a sentence to the documentation of R6Class() mentioning that sometimes **"for inheriting classes set \code{parentenv} to e.g. \code{asNamespace('mypackage')} to get access to the package's unexported functions"**

Long format:

I stumbled about this problem building a package looking something like this:

#' some helper function
my_function <- function(){
  message("Found it!")
}

#' a super class to inherit from
#' @export
super_class <-
  R6::R6Class(
    classname = "super_class",
    public    =
      list(
        super_class_action =
          function(){
            my_function()
          }
      )
  )

#' a sub_class that inherits
#' @export
sub_class <-
  R6::R6Class(
    classname = "sub_class",
    inherit   = super_class,
    parent_env = parent.frame(),
    public    =
      list(
        sub_class_action =
          function(){
            my_function()
          }
      )
  )

Now the problem is that -- when building a package like that -- an instance of the sub class will not be able to find my_function():

library(mypackage)
dings <- sub_class$new()
dings$sub_class_action()
## Error in dings$sub_class_action() : could not find function "my_function"

Thinking about it and doing some research it is clear, that it has to work that way since the instance is looking for my_function() within super_class but actually it is to be found within mypackage - right?

The solution (thanks to Mark and Thomas) is to e.g. use the parent_env argument of R6Class () so that my_function() can be found, e.g. setting it to the package environment:

#' a sub_class that inherits
#' @export
sub_class <-
  R6::R6Class(
    classname = "sub_class",
    inherit   = super_class,
    parent_env = asNamespace('mypackage'),
    public    =
      list(
        sub_class_action =
          function(){
            my_function()
          }
      )
  )
hadley commented 7 years ago

I'm reasonable certain you should simply not set parent_env. If you call parent.frame() from the top-level (as you are), it returns global_env().

petermeissner commented 6 years ago

Me again ... because I ran into this again ... this time from a slightly other angle.

... I think this problem can occur reasonable often and is reasonable hard to understand / find a solution for to maybe get reconsidered / mentioned in documentation