New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mutable: Modify values in place #52
Conversation
Signed-off-by: Uwe Klotz <uwe.klotz@slowtec.de>
339af76
to
e6ad6fe
Compare
I'm curious why you consider that. As for your feature request, that's already possible: let mut lock = mutable.lock_mut();
if some_condition(lock) {
*lock = new_value;
} This will only trigger a change if This is quite a lot more convenient and flexible than your approach. It also works correctly with You simply use the lock as normal (it auto-derefs to the Mutable's value), and it will automatically determine if you used the lock mutably or not. If you used it mutably, then it will trigger a change, otherwise it doesn't. |
Your proposed approach does not allow to invoke a Borrowing mutably is a low-level syntactic concept while modification is a high-level semantic concept that involves business logic. Only the invoked function could provide the information if it has actually modified the value in-place or not. |
That's generally a good thing. It should be difficult to miss updates, because that results in very hard-to-debug problems. Your approach makes it very easy to accidentally miss an update, which leads to bugs. It's better to have too many updates rather than too few, since the former causes performance problems but the latter causes behavior bugs. And it's always possible for the downstream consumer to use things like However, you are right that sometimes the user wants to intentionally avoid triggering an update even when mutating the value. This should be possible, but not by accident. Something like this should be a good API: let mut lock = mutable.lock_mut();
if some_condition(lock) {
*lock = new_value;
}
MutableLockMut::mark_no_change(&mut lock); The exact name can be bikeshedded. |
Manually resetting the |
Btw, |
Yes, it should be less convenient, because it is an uncommon use case, and it's a footgun which can easily cause bugs. Rust's design philosophy is to avoid bugs and footguns. Also, it's not necessarily more statements: it only needs 1 statement at the end, whereas with your approach you need minimum 2 statements (one for If you are concerned about spurious updates, you should be using something like
Is it? The point of |
My use case involves non-primitive, non-comparable values, i.e. complex state that is mutated only partially. |
I had been planning on implementing a However, that's not really what I'm asking: I need to better understand your state and how you're using it, since there might be a better way of doing things. I have written large apps with Signals, and I've never once felt the need for what you're asking for, so either you're doing something quite unusual (and I want to understand it so I can support it), or there's a different way of structuring your code. |
As you seem to focus on different use cases I will close this PR. |
That's not at all what I'm saying, I'm asking because I want to understand your use case, so I can improve |
I tried to explain it. |
Yes, but I need more details: like your type definitions, how you are consuming the Signals, what your app is doing, etc. |
See tokio-rs/tokio#4591 for a discussion why this is useful and mandatory for implementing certain FRP use cases.
Currently, I am using
std::tokio::watch
that I consider more mature than this crate. But I would actually prefer using a dedicated crate with less dependencies for this purpose.