Add useful methods to UseStateHandle & UseReducerHandle#3422
Add useful methods to UseStateHandle & UseReducerHandle#3422its-the-shrimp wants to merge 2 commits intoyewstack:masterfrom
UseStateHandle & UseReducerHandle#3422Conversation
|
Visit the preview URL for this PR (updated for commit 174d139): https://yew-rs-api--pr3422-add-handle-methods-dx5xc4eu.web.app (expires Thu, 05 Oct 2023 20:54:58 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 |
Benchmark - SSRYew MasterDetails
Pull RequestDetails
|
Size ComparisonDetails
✅ None of the examples has changed their size significantly. |
| /// Returns the inner value of the handle. | ||
| pub fn get(&self) -> Rc<T> { | ||
| // Safety: `UseStateReducer<T>` is `repr(transparent)` and only contains `T` | ||
| unsafe { transmute(self.inner.get()) } |
There was a problem hiding this comment.
Can we avoid the transmute somehow?
There was a problem hiding this comment.
not really, this transmute converts between Rc<UseStateReducer<T>> and Rc<T>, there's not much you can do with a value inside an Rc
There was a problem hiding this comment.
You would need to convert Rc<UseStateReducer<T>> -> Rc<T> (assuming T is not guaranteed to be Clone) some other way then (maybe via Any?). I think using repr(transparent) was a brilliant idea for Rcs and now I hope Rust makes it like a safe trait / Rc function.
futursolo
left a comment
There was a problem hiding this comment.
I am not in favour of this pull request.
We have discussed in some previous pull requests. How a state is stored should be an implementation detail. Not exposing this allows us to switch the underlying implementation at a later time.
e.g.:
To implement concurrent mode, we will need to have multiple schedulers and states need to be associated with a scheduler ID .
I am not exactly settled on how this would be associated.
This pull request rules out the following possibility.
struct UseStateReducer<T> {
inner: T,
scheduler_id: Id,
}|
The PR does restrict the flexibility in implementation, but on the other hand, how likely is the implementation to change? The current approach works just fine, obtaining/setting the value doesn't require much indirection, and the new methods will allow for easier usage of non(-trivially)-clonable types in the aforementioned handle types. |
|
@futursolo Provide other solutions of being able to encapsulate/not clone
#[derive(Clone, ...)] // also ImplicitClone
struct UseStateValue<T> {
inner: Rc<T>, // using same `repr(transparent)`/`transmute` trick
}
impl Deref for UseStateValue<T> {
type Target = T;
...
}
Also possible that |
|
The medium case isn't good because oftentimes the value needs to be cloned after getting it out of the state, forcing T to be Clone when it can be avoided. It's either that or recreating the Rc that we just took the value out of. Yew playground has a component that suffers from this exact same thing today when attaching the change listener to Monaco editor Concurrent mode, when implemented, will most likely come with breaking changes of its own. I'd rather remove these methods then, providing a suitable alternative, than not add them in the first place |
|
Btw, just as an idea, the fact that those new methods return an Rc does not mean they lock us to one impl, even if we switch to an impl that'll make those structs contain just an interned ID, as long as there's a way to access the interned value, we will be able to provide it in an Rc, either by cloning the Rc if that's how the object will be stored, or by allocating it in an Rc, after which we'd add a warning to the docs of those methods regarding their perf implications |
Description
This PR adds:
UseStateHandle::get&UseReducerHandle::getthat return the contained value of the handle in the form in which it's stored internally: in an Rc; These 2 methods will make it easier to work with non(-trivially)-clonable types in said containers;UseStateHandle::into_inner&UseReducerHandle::into_innerthat consume the handle and return its 2 main parts: the inner value and the setter/dispatcher associated with the handle. These methods will allow for avoiding cloning in certain contexts where one would have to useget()+setter()/dispatcher()otherwise.Checklist