r-lib / R6

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

assigning function from another namespace via `set` strips function of original environment #164

Closed yonicd closed 5 years ago

yonicd commented 5 years ago

I am trying to place a function from a installed package using set, in the example below stats::rbinom.

the function's environment is replaced when initializing on the R6 class. This causes the runction itself not to be able to run since it can't locate non exported functions from the parent namespace.

Is there a simple way to do this in R6?

Simple <- R6::R6Class("Simple",
                      public = list(
                        x = 1,
                        getx = function() self$x
                      )
)

Simple$set(which = 'public',name = 'foo',stats::rbinom)

Simple$public_methods$foo
#> function (n, size, prob) 
#> .Call(C_rbinom, n, size, prob)
#> <bytecode: 0x7f9c3dc78ab8>
#> <environment: namespace:stats>

obj <- Simple$new()

get('foo',envir = obj)
#> function (n, size, prob) 
#> .Call(C_rbinom, n, size, prob)
#> <environment: 0x7f9c3dee7e38>

obj$foo(n = 1,size = 0,prob = .3)
#> Error in obj$foo(n = 1, size = 0, prob = 0.3): object 'C_rbinom' not found

Created on 2018-10-12 by the reprex package (v0.2.1)

wch commented 5 years ago

Any members of Simple that are functions are considered methods, and so they'll have their environment changed when an object of class Simple is instantiated.

If you want to work around this, you can either:

Assign foo in the initialize method:

Simple <- R6::R6Class("Simple",
  public = list(
    initialize = function() {
      self$foo <- stats::rbinom
    },
    foo = NULL
  )
)

Make foo a wrapper function that calls the function you want.

Simple <- R6::R6Class("Simple",
  public = list(
    foo = function(...) stats::rbinom(...)
  )
)

In this case I think it makes more sense to use the second option.