r-lib / R6

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

Active bindings turned into constants during package build #152

Closed mllg closed 5 years ago

mllg commented 5 years ago

Here is a small package to illustrate the issue:

https://github.com/mllg/r6pkg

Everything works out fine while loading the package interactively (using devtools' load_all()):

load_all()
print(bar)
<foo>
  Public:
    clone: function (deep = FALSE)
    x: 10
    x_squared: active binding

The active binding is lost after installing and loading the package in a fresh R session via library():

library(r6pkg)
print(bar)
<foo>
  Public:
    clone: function (deep = FALSE)
    x: 10
    x_squared: 100

Looks like the binding gets evaluated during R CMD build and the returned value is stored instead.

wch commented 5 years ago

It looks like this is what R does in packages: active bindings get saved as regular values.

If you add this to your package, the same thing happens:

#' @export
e <- new.env()
makeActiveBinding("x", function() runif(1), e)

Then after installing the package:

e$x
#> [1] 0.1425588
e$x
#> [1] 0.1425588
bindingIsActive("x", e)
#> [1] FALSE

Perhaps it's worth asking about on the R-devel mailing list?

mllg commented 5 years ago

Can confirm this one. I've updated the package to also include your code.

> library(r6pkg)
> unique(replicate(10, r6$x))
[1] 0.5698038
> unique(replicate(10, env$x))
[1] 0.262672

@kalibera, is this related to the bytecode compiler?

mllg commented 5 years ago

NB: saveRDS() + loadRDS() is not affected.

kalibera commented 5 years ago

Active bindings are preserved on serialization/deserialization, but one has to serialize them as bindings (not values) - so one has to serialize at least the environment they are part of.

kalibera commented 5 years ago

Active bindings are however not preserved when a package is being prepared for lazy loading (during package installation). The lazy loading database is already created with concrete values for active bindings.

mllg commented 5 years ago

So this is a feature, not a bug? 😕

mllg commented 5 years ago

Workaround: construct objects with active bindings in .onLoad().

kalibera commented 5 years ago

It is probably unintentional, but may not be trivial to fix (could impact performance of package installation, would require some change in lazy loading database format). So if you can use .onLoad that would be great and would also work for released versions of R.