Add `std::mem::{swap, replace, take}` to the prelude

FWIW, I really enjoy doing mem::swap(&mut a, &mut b); the same for take and replace.
I find that it helps understand what's happening, that it's swapping the memory behind the pointers and not the pointers or something else.

6 Likes

I nearly never use any of these three functions, but if i were to use them i'd only want the core::mem versions. I can't imagine any scenario where i'd ever want to make some other function named just swap and have it be different from core::mem::swap. Further, I can't imagine wanting to ever have to look at a code base where someone has done this themselves.

So, yes, a vote strongly in favor of putting these in the prelude as a "soft reservation" that these functions should always be the official way for that word to be a verb.

EIDT: size_of and align_of also, please :3

2 Likes

For me, they are rarely used, and when used I'd prefer them to be with mem:: prefix.

I'd say it swaps the values behind the references which is a bit of a higher-level description.

1 Like

One random thought: don't spell it std::swap, ever, because mem::swapRust has subtly different behavior from std::swapC++, due to C++'s reference semantics.

Specifically, std::swap(a, b)C++, which I believe is also allowed to be spelled swap(a, b)C++ depending on overloads, swaps the values semantically located in a and b.

On the other hand, mem::swap(a, b)Rust requires that a and b are &mut _, and swaps the values behind these references (which are pointers passed by copy in C++ parlance). To swap a and b, as in the C++ invocation, you write mem::swap(&mut a, &mut b)Rust, or a very ill-advised swap!(a, b)Rust macro.

This isn't a be-all-end-all, of course. Rust isn't C++, and there are many C++ things you need to unlearn to write good Rust. If we add swap to the prelude as a vocabulary item, then it's just another thing you'll need to learn to make the transition. But mem::swap works and is clear to what it's doing, and clearly considered idiomatic by many. Why add another speedbump and potential pitfall, when you could just not?

And that said,

I strongly disagree with this use of the prelude. The prelude should be for items (with unambiguous names) that most Rust programs are expected to need and all Rust programs should know about, not a place to put every std item name that happens to have only one reasonable interpretation. Especially since there's no lint for defining a name that hides a prelude name (maybe there should be), so it would be possible to get the wrong impl if you didn't know it was in the prelude (say, because it was added after you started writing Rust).

And another veto for adding mem::size_of<T> to the prelude; heap::size_of<T> is another perfectly reasonable function (if not one with a simple impl).

4 Likes

This is so very deeply subjective.

Not only do I not quite know what you think that free function would do, there is no such function in the standard library.

My point is that you're explicitly not asking for swap in the prelude because it's generally useful, but because you don't want anyone else to provide a free function called swap. This is clearly not what the prelude is for.

heap::size_of would return the amount of heap memory a type uses (recursively?). This isn't saying that this is a function that std should provide, or even the interface that a crate would provide, but that another free function called size_of is viable, alongside mem::size_of, as a counterargument against adding mem::size_of to the prelude.

Yes, what is generally applicable enough to deserve being in the prelude is a very subjective question to ask. My point here is that being a name with one reasonable interpretation/implementation that the std provides is a necessary but not sufficient qualifier to inclusion in the prelude.

Since I don't see it mentioned, I'll add that there are also the unsafe versions for pointers: std::ptr::swap and std::ptr::replace. Admittedly they have the same semantics, and in contexts where both would compile are interchangeable with the ones in mem. I've also just found out that both are available as methods on pointers.

4 Likes

The ptr::swap method also allows that both input pointers are equal, but otherwise they are equivalent.

We've used swap and similar in std in BinaryHeap algorithms, Vec dedup, Vec retain and so on. But as time goes on these safer and simpler implementations have been replaced by algorithms that don't use swap (to save redundant writing). That's another anecdote which says that swap is very useful for some algorithms - that's good - but not it might not stay if we rewrite it using more unsafe-marked code.

Given how many people have hearted my suggestion to add std::mem to the 2021 prelude I think that I will go and make an RFC for that. Especially since the discussion here has died down.

2 Likes

Having mem in the prelude would be nice. While at it, any way to deprecate drop? We tend to prefer using it as mem::drop anyway.

1 Like

I doubt that will happen, but if the RFC does go through then you can do it in your own code.

Since when can you deprecate an import?

That is not what I meant. I meant that if std::mem is added to the prelude then in your own code you can use mem::drop.

Well how do you lint against prelude drop then?

Who is "we" in the "we tend to prefer"? That organization can just put it in their style guide.

3 Likes

This discussion about drop is a derail for this topic. Please start a different thread if anyone has proposals to make about drop (but please remember that proposals should start with details of the problem being solved, who is affected by the problem, and why the proposed change is the best way to solve it).

5 Likes

I’m working on a prelude update RFC that will include this. PR coming soon!

6 Likes

Thanks for the notice.

See A new prelude for the 2021 edition by djc · Pull Request #3090 · rust-lang/rfcs · GitHub.

2 Likes