You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Don't get me wrong, I think by default the above behavior is correct. But I would somehow slightly adapt my class definition such that the above is possible.
In R only environments provide in-place updates so I tried building a solution around that.
A naive approach would be define a class with a class_environment as parent. But this is not possible duo: #290
So a work around is to manually manage the environment within the S7 object and have getters and setters update that.
T<- new_class(
"T",
properties=list(
.storage= new_property(
class=class_environment,
setter= \(self, value) {
if (is.null(self@.storage)) {
self@.storage<-valuereturn(self)
}
stop("Cannot set @.storage after creation")
}
),
a= new_property(
class=class_numeric,
setter= \(self, value) {
stopifnot("@a should be a numeric"= is.numeric(value))
assign('a', value, self@.storage)
self
},
getter= \(self) get('a', self@.storage),
validator= \(value) print("I never get called! Even not with `S7::validate()`")
)
),
constructor= \(a=numeric(0L)) {
storage<- new.env(parent= emptyenv())
new_object(S7_object(), .storage=storage, a=a)
}
)
The problems with the approach
This works but as the example highlights it has a couple of problems:
Ideally my code should use the same type checking as is done internally by S7.
The error raised does not nicely gather with other validation errors and is formatted differently.
Custom validators do not work anymore because we are defining a dynamic property. So this also needs to be done at the setter property.
It is quite verbose to define a class with the desired behavior with what feels like a lot of boilerplate code. Making my code less readable and comprehensive to understand.
Work arounds:
The current solutions I have at my disposals are:
Live with the above downsides: But manually type checking feels like a job for S7 and does not interact anymore with S7::validate(). It also make my code less readable.
Just directly work with environments: But this defeats the purpose of using S7 in the first place.. I want to be able to structurally define my classes and have them automatically validated.
Use R6: but then I have to mix 2 OOP systems in one code base.. Making my code base more complex + I do not have the automatic type validation. Also I am personally not the biggest fan of encapsulated OOP and would rather base my solution on S7.
Why do I care?
When developing Applications (like shiny apps). You have a long running process and usually objects are created once on initialization of the app (or session) and various callbacks drive the behavior of your server (in shiny these are observes / reactive and renders).
Objects that provide in place updates are perfect to managing state in an app.
I know that in shiny you can manage state with reactiveVal(ues) but:
in my case I do not care about further down process triggering so it feels like unnecessary overhead.
reactivesValues must be consumed within a reactive context which is not the case if I want to manage state outside of my sessions. I then have to spam isolates(). In my case I have global "App" object that lives on the process level not session level.
Also with reactiveValues I do not have the nice automatic type validation and class structure that S7 provides.
There are plenty of other application servers out there that are not shiny. And not supporting this is holding back maybe a new server framework is based on S7.
Sorry for the long post, but it would be cool if something like this can get supported or at least address the outstanding issues with the current approach.
The text was updated successfully, but these errors were encountered:
I think the place to start would be to resolve #290 so that you can inherit from environments. But this will require careful analysis to ensure that we don't reintroduce any subtle bugs.
(But I do wonder if mutable S7 objects are going to be generally confusing; IMO there's something nice about the connection between mutability and $ methods found in R6).
Would it be possible to support in place updates of properties like R6?
Eg. that with a slight adjustment of the class definition the object would behave as follows:
Don't get me wrong, I think by default the above behavior is correct. But I would somehow slightly adapt my class definition such that the above is possible.
In R only environments provide in-place updates so I tried building a solution around that.
A naive approach would be define a class with a
class_environment
as parent. But this is not possible duo: #290So a work around is to manually manage the environment within the S7 object and have getters and setters update that.
The problems with the approach
This works but as the example highlights it has a couple of problems:
Work arounds:
The current solutions I have at my disposals are:
S7::validate()
. It also make my code less readable.Why do I care?
When developing Applications (like shiny apps). You have a long running process and usually objects are created once on initialization of the app (or session) and various callbacks drive the behavior of your server (in shiny these are observes / reactive and renders).
Objects that provide in place updates are perfect to managing state in an app.
I know that in shiny you can manage state with
reactiveVal(ues)
but:Sorry for the long post, but it would be cool if something like this can get supported or at least address the outstanding issues with the current approach.
The text was updated successfully, but these errors were encountered: