As I put in the other thread, the core thing is that -- unlike every other trait -- implementing Deref
changes name resolution for method calls. This is a huge deal.
So the core property that smart pointers have is that when you're using a Box<T>
you almost always are actually using the T
inside it, not the box-ness of it. As such, Box
is careful not to add methods that could conflict with yours. When it wants to offer more functionality, it does so with associated functions like Box in std::boxed - Rust that aren't picked up in method name resolution.
And places where this doesn't happen -- trait methods being the important one -- it can be a trap. For example, because of ambiguity between foo.clone()
and foo.deref().clone()
the docs for Arc
used to say
The
Arc::clone(&from)
syntax is the most idiomatic because it conveys more explicitly the meaning of the code. In the example above, this syntax makes it easier to see that this code is creating a new reference rather than copying the whole content of foo.
~ std::sync::Arc - Rust
This is also why things like Debug
on Arc
just delegate to the implementation for the inner type -- it's trying to behave like it's not there.
And I'll throw in NonZeroU32
as another example of a newtype that's applying a restriction to the wrapped value but still doesn't Deref
to it.