-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
pre-RFC: Add a way to insert into a collection, then return a reference to the inserted item in one operation. #3343
Comments
for the types with mutable members (so not sets) imho the returned reference should be a mutable reference, the caller can easily convert to a shared reference if they desire but not the other way around. |
What is here that cannot already be done with the safe entry API (although it's missing for sets)? let mut set: HashMap<String, ()>;
set.entry(String::from("abc")).insert_entry(()).get() |
I certainly see the "why not?" appeal here, and TBH I did consider this while writing the post. Ultimately I think it's a tradeoff between consistency and functionality. It might be surprising for some users to find that:
Ultimately I decided to go for the consistency and just return an immutable reference regardless. We can always add But yeah admittedly I am pretty torn on what to do here. I would like to know the various opinions of the broader community. |
I'm entirely in agreement here that in the specific case of So again it comes down to a tradeoff with consistency I suppose. It would be nice if this family of methods is universal across all collections; but I also fully admit that this will come with the downside of duplication of functionality. Honestly, I don't know which path forward is better either. After all, that's why this is a pre-RFC, sorry ¯\_(ツ)_/¯ |
The proposed functions are unfortunately not all that practical because they cause the underlying collection to be borrowed mutably, meaning that one cannot call any function or get any other reference out of them.
|
Yikes. That's a very good point (unfortunately) that I overlooked. I just assumed that since we're only retaining an immutable reference, the borrow checker would see that the collection is no longer being borrowed mutably. Speaking of which, I'm very curious whether there is actually a safety reason behind this behaviour, or is it just a technical limitation: why doesn't the borrow checker see that the retained reference has been "downgraded"? It seems to me like all the information the borrow checker would need to deduce this is available in the function signature. |
A simple counterexample: fn demut(x: &mut AtomicU32) -> &u32 {
&*x.get_mut()
}
let mut x = AtomicU32::new(1);
let y = demut(&mut x);
// y is now an immutable &u32 that equals &1
x.store(2, SeqCst);
// is *y now 1 or 2? |
@cyqsimon As @SOF3 's example shows, the borrow checker can't see that because that would be essentially an API guarantee, not an implementation detail. Besides, there's the "design rule" that the borrow checker can't depend on information from inside of function bodies, as those are considered implementation details too. There has been some ideas of having a "downgrading annotation" (e.g. https://internals.rust-lang.org/t/relaxing-the-borrow-checker-for-fn-mut-self-t/3256/21), but no concrete proposals, and I doubt the time is ripe for such a proposal at the moment. |
I ran across this issue today when I'm attempting to write a function like this:
To my surprise, there is no easy way to do this with
HashSet
, or for that matter, with any collection. I ended up having to write this:This is obviously bad for a multitude of reasons:
Player::clone
callHashset::get
callunwrap
So I asked on the Rust-lang discord guild here, and Yand.rs gave this solution:
... but also had this to say:
My proposition
Add a family of associated functions that provide this capability to all collections:
Potential questions
*_get_mut
variants too?VecDeque
andLinkedList
already havefront
andback
methods. Do they makepush_front_get
andpush_back_get
redundant?(Option<V>, &V)
instead)(&K, &V, Option<V>)
or((&K, &V), Option<V>)
)The text was updated successfully, but these errors were encountered: