Why are smart pointers not `Copy`-able?

Some time ago I remember people bringing up that Rust tends to favour performance over ergonomics and accessibility, with dyn Trait -s, their vtables and downcasting on demand, (generally) frowned upon - as static compile-time dispatch tends be quite a bit faster.

I also vaguely remember someone bringing up that one could, effectively, recreate their own Python/Lua/JS in Rust - by simply wrapping everything up in Rc<RefCell<?>> or Arc<Mutex<?>>, depending on the case at hand. Assuming one has considered all the performance applications, the reasons why it's discouraged / not recommended / unnecessary you name it, I am rather curious.

Why have the smart pointers been restricted from Copy? Perhaps a more general question would be in order for the implementation / restrictions on the Copy itself, which explicitly states that:

Generalizing the latter case, any type implementing Drop can’t be Copy , because it’s managing some resource besides its own size_of::<T> bytes.

Not sure I understand the full reasoning behind it. What's so problematic about declaring a type with an inner (A)Rc<T>, and making it automatically clone() itself via a #[derive(Clone, Copy)] on each move? Why is there any need to care whether any additional resources are being managed? Whether or not a Drop has to be called, at the end of a lifetime?

There are two RFCs (one and two) that seem to have already brought a rather substantial amount of attention on the matter. Yet even after reading them, I don't understand the "why".

The Copy trait has a very specific technical meaning in Rust, that byte-for-byte copying of the value will produce two valid objects: one at the original location and another at the destination. This is incompatible with anything that uses Drop to implement the RAII pattern, as now you have two objects that will each try to free whatever resource (e.g. memory) is being managed.

Auto-clone is a possibility which has been discussed several times; if a version of it is adopted, it will be separate from Copy because of the technical differences. In general, Rust likes to keep “heavy” operations like deep-copying hashtables explicit, but it’s hard to draw a neat line between that sort of heavy clone and the lightweight ones of Rc/Arc. The current Rust answer for that is to be conservative and only allow the trivial memcpy clone/copy operation to happen automatically.

12 Likes

Great answer. Reminded me that I recently read something about making the ergonomics around Clone better:

https://smallcultfollowing.com/babysteps/blog/2024/06/21/claim-auto-and-otherwise/

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.