Closed yonicd closed 5 years ago
this is a solution, but kind of hacky
Simple <- function(){
R6::R6Class("Simple",
public = list(
x = 1,
getx = function() self$x
)
)
}
obj <- Simple()
obj$set(which = 'public',name = 'new_field','aaa')
obj
#> <Simple> object generator
#> Public:
#> x: 1
#> new_field: aaa
#> getx: function ()
#> clone: function (deep = FALSE)
#> Parent env: <environment: 0x7fbeabe4f340>
#> Locked objects: TRUE
#> Locked class: FALSE
#> Portable: TRUE
obj2 <- Simple()
obj2
#> <Simple> object generator
#> Public:
#> x: 1
#> getx: function ()
#> clone: function (deep = FALSE)
#> Parent env: <environment: 0x7fbeaceed2c8>
#> Locked objects: TRUE
#> Locked class: FALSE
#> Portable: TRUE
Created on 2018-09-26 by the reprex package (v0.2.1)
I wouldn't say that this is related to inheritance; the issue is that the generator object is an environment, so it has reference semantics.
is.environment(Simple)
#> [1] TRUE
That's why you can call Simple$set()
, and have it alter the Simple
object, instead of having to do something like Simple <- Simple$set()
.
I think your workaround makes sense here.
What is the use case for this?
a good analogy would be purrr::partial
.
I have an R6 object in a package that characterizes a trial.
In it there are public fields/methods that represent a broad range of parts that are included in a stage of a generic trial.
In reality though trial specific fields/methods need to be added to the R6 by the user, where new()
is treated as a trial scenario.
This is where the set()
function comes in. Since set()
can only be called before new()
and clone()
is only available after new()
then I can't effectively clone the R6 object.
Since the R6 is from the namespace of the package, once the set()
is invoked it traverses back into the object in the package, which is a real problem because the next time in the session the user wants to use the package R6 object to create a new trial generator they have public fields/methods from a previous trial in it.
Could encapsulate
be changed a bit to create new environments every time it is called? that way the same basic functionality of obj <- Simple; obj$set()
that you described above would still be possible, but the basic generator of Simple would be unchanged ready for another clone.
I have an R6 object in a package that characterizes a trial.
Do you mean you have an R6 class in a package?
Can you just make a subclass of it when you want to add trial-specific stuff, like this:
Simple2 <- R6Class("Simple2",
inherit = Simple
)
Simple2$set( .... )
obj <- Simple2$new()
To me, that seems like the natural way to handle this kind of case.
Changing encapsulate
would not help here; it does something different from what you're implying.
I'll try that. thanks for the tip!
I am seeing a behavior of reverse inheritance that I don't know how to break.
If I define an
R6
(Simple
), then define a new object (obj
) add a new field to obj viaobj$set
, thenSimple
is also manipulated.(Not sure what the right title for the issue should be)
Created on 2018-09-26 by the reprex package (v0.2.1)