Note the &self to allow this to be used for interior mutability.
There could be InteriorOpAssign versions that use &self for all the other operators as well:
InteriorAddAssign => :+=
InteriorSubAssign => :-=
Etc...
Bonus
As a bonus, (I'm not sure this can work) implement InteriorAccess to use ->
So instead of:
ref_cell.borrow_mut().some_method()
You can use:
ref_cell->some_method()
It might cause issues for the parser because it is used for function returns, but if not then this syntax could cut down a lot on a lot of boilerplate working with interior mutability.
We don’t even have traits for customizing “assignment” operations for the non-interior-mutable case; we also don’t have special syntax for borrow_mut()-style projections in the non-interior-mutable case.
A main design choice of Rust is to keep interior mutability limited / the exceptional case, as far as resonably possible; the syntax overhead is not a limitation, it’s intentional.
It's pretty much baked into the foundational philosophy of the language, as evidenced by the fact that regular mutability has syntax support (and has had it since before 1.0) where interior mutability does not.
That syntactic divide was no accident. It follows from a recognition that interior mutability occupies a point on a spectrum between "useful" (eg perf optimization) and "necessary" (in the occasional case where regular CREW semantics are too restrictive).
Right, but the behavior of = is fixed and not overloadable. Yet, overloadable assignment-like operations for a neat shorter syntax would be something that users might want to use. And if we offer it only for interior-mutable primitives, it’d be like encouraging interior mutability onto certain APIs only for the sake of syntactic concisenes.
On the other hand, there are good reasons in favor of keeping assignment non-overloaded; ultimately that’s the only way to really guarantee to all readers of Rust code that writing = really is generally a rather cheap operation.
It would be a circular argument if the goal was to argue that this should continue to be part of Rust’s philosophy. However, for the goal of saying what is currently the case, it doesn’t seem circular. Do keep in mind, of course, that breaking from the current ethos of the language requires a fairly strong motivation to overpower concerns about churn or confusion.
Well… we’re talking not about just any language feature, but specifically about new operators. New syntax like that has a higher bar for being considered, and thus it’s important to consider all potential downsides / counter-arguments. Also compare this document [in particular this section] for some more documented thoughts/principles, also touching on things like “new operators”.
Changes that would break existing Rust code are non-starters.
As far as I can tell, my := proposal would not cause any breaking changes.
My -> proposal I am unsure about.
For instance, we don’t want to make changes that make code easier to write but harder to read, or changes that make code more error-prone to modify and maintain.
I feel like my proposal makes it both easier to read and write code that deals with internal mutability.
If it's not too much work, I might have a go at implementing this myself so people can try it first.
By the way, a current way to “assign” (rather than “replace”, i.e. not getting back the previous value as an output) inside of a RefCell, that actually uses the assignment operator, would be
*data.ref_cell.borrow_mut() = Some(new_value);
instead of the
data.ref_cell.replace(Some(new_value));
mentioned in the original post of this thread.
Given mem::replace is must_use already, this makes me wonder if RefCell::replace should be must_use, too.
A better example might be Cell, since it doesn't let you do that. I imagine this feature coming into play whenever you have a type that doesn't want to hand out references to its interior but still wants to allow you to mutate it. C# properties are a similar thing (and maybe something closer to those would be a better idea, idk).
Another use case for an overloadable assignment unrelated to interior mutability is inserting items into a HashMap, which currently cannot be done using map[key] = ... syntax, because it could not avoid panicking on an absent key, because right now the only trait for this is IndexMut which requires returning &mut to an existing, initialized place. In general, Rust assignment currently demands &mut, but producing &mut is not always possible or wise even when an assignment-like operation is possible.