Rc::clone(&r) or r.clone()?

I think it's fair to say that the fully qualified form being the only idiomatic way is no longer the case. [1] In fact, that was agreed to by FCP.

The history is somewhat interesting if you're into that kind of thing.

I saw these:

And then looking up where the doc changes came from,

That points the origin of the recommendation, clippy lint, and book changes

And the motivation was to emphasize that it was a shallow and inexpensive operation.


With that in mind, here's what I would consider reasonable changes (modulo my ability to word good) in the linked book sections and some std documentation:

  • In the last paragraph here, don't imply it's not the only idiomatic way, and ditch the "deep-copy" talk.
     We could have called `a.clone()` rather than `Rc::clone(&a)`,
    -but Rust’s convention is to use `Rc::clone` in this case.
    +and doing so is one convention.  However,  we're following a
    +convention that uses the fully qualified form to emphasize the
    +low performance cost and shallow nature of cloning the `Rc`.
    -The implementation of `Rc::clone` doesn’t make a deep copy of
    -all the data like most types’ implementations of `clone` do.
     The call to `Rc::clone` only increments the reference count,
     which doesn’t take much time.
    -Deep copies of data can take a lot of time.
     By using `Rc::clone` for reference counting, we can visually
    -distinguish between the deep-copy kinds of clones and
    +distinguish between potentially expensive 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 to `Rc::clone`.
    
  • In the last paragraph here, seems like a good place to note the lack of DeepClone.
     When you see a call to clone, you know that some arbitrary
     code is being executed and that code may be expensive. It’s a
     visual indicator that something different is going on.
    +Note that while it is common for clone to give a deep copy of
    +the owned data, this is not always the case, as we will explore
    +in chapter 15.  There is no trait in the standard library for
    +making a recursively deep copy.
    
  • And also here.
     The `Clone` trait allows you to explicitly
    -create a deep copy of a value,
    +duplicate a value,
     and the duplication process might involve running arbitrary code
     and copying heap data. See the “Ways Variables and Data Interact:
     Clone” section in Chapter 4 for more information on `Clone`.
    
    +// And right before the talk about `Copy`...
    +
    +Note that while a typical implementation of `Clone` may perform
    +a deep copy, `Clone` is intended to logically duplicate values
    +and does not *guarantee* a deep copy.  As one example,
    +references themselves implement `Clone`.  As another example,
    +shared ownership smart pointers such as `Rc` and `Arc` only
    +update their reference counts and create new smart pointers to
    +the same shared data.
    +
    +Derived and other recursive implementations of `Clone` also
    +typically respect the `Clone` implementations of their contained
    +types.  A clone of a `Vec<Rc<Widget>>` will newly allocated `Vec`,
    +for example, but the `Rc<Widget>`s in the new `Vec` will be smart
    +pointers to the same set of shared `Widget`s.
    +
    +Rust has no trait exclusively for deep copies.
    
  • Remove the "idiomatic" language here.
  • Add some language about the lack of deep copies here.
    +Note that `Clone` does not necessarily provide a "deep copy"
    +of a type's data.  `Rc` and `Arc`, for example, increment
    +reference counters and return a shallow copy of themselves
    +in order to provided shared ownership.  Rust has no trait
    +exclusively for deep copies.

  1. I'm not sure it ever actually idiomatic, really:

    The recommendation is also not followed in this repo. It is hard to figure out how many calls there are of the .clone() form, but there are 1550 uses of Arc and only 65 uses of Arc::clone. The recommendation has existed for over two years.

    ↩︎
5 Likes