We've been told that we should always write Rc::clone(&r)
and not r.clone()
.
In the book we read:
By using
Rc::clone
for reference counting, we can visually distinguish between the deep-copy kinds of clones and the kinds of clones that increase the reference count. When looking for performance problems in the code, we only need to consider the deep-copy clones and can disregard calls toRc::clone
https://doc.rust-lang.org/book/ch15-04-rc.html#using-rct-to-share-data
On the other hand, the document of the Clone trait
says:
[Clone] differs from Copy in that Copy is implicit and an inexpensive bit-wise copy, while Clone is always explicit and may or may not be expensive...
...but you may reimplement
Clone
and run arbitrary code.
And to some extent it clarifies that clone
is not necessarily a deep copy. However, currently in the book in several places clone
is used like a deep copy:
As we know, when we deep copy object a
and create object b
, that means we'll get two independent objects a
and b
. There should be no way that manipulating a
's state affects b
's state and vice versa.
When we clone
an Rc
, as long as the data to which it is pointing is immutable, we'll get an independent copy. However, if we make that data mutable, the clone created by Rc::clone
will not be an independent copy. If a program assumes that an object which implements the Clone
trait makes independent copies with its clone
function, an Rc which contains a RefCell
can become problematic. (like this example or this example)
Is it really necessary and is it a good idea to recommend calling clone
like an associated function for shared smart pointers? (i.e. like Rc::clone(&r)
and not r.clone()
) This is not just about Rc
. Any struct that contains a shared smart pointer will be subject to this recommendation. In my opinion this is just adding unnecessary complexity to the rust development. Now a programmer can be a "bad rust developer" just because he's used r.clone()
in his code. This type of recommendations are always troublesome.
For this reason, I suggest that one of these solutions be chosen:
- We can introduce a new trait for deep copy and then deprecate all current implementations of the
Clone
trait that are doing a deep copy. (the new trait will replace them) - We can introduce a trait for costume copy semantics or even without introducing a new trait, we deprecate all implementations of the
Clone
trait that are performing some type of costume/shallow copy. For exampleRc::clone
should be deprecated and get replaced with a function likeRc::share
This will reduce the probability of misunderstandings.