Skip to content

Commit 1b65edf

Browse files
author
John-Mark Allen
committed
Re-draft Deref docs
Make general advice more explicit and note the difference between generic and specific implementations.
1 parent c14f67c commit 1b65edf

File tree

1 file changed

+75
-45
lines changed

1 file changed

+75
-45
lines changed

library/core/src/ops/deref.rs

+75-45
Original file line numberDiff line numberDiff line change
@@ -3,70 +3,100 @@
33
/// In addition to being used for explicit dereferencing operations with the
44
/// (unary) `*` operator in immutable contexts, `Deref` is also used implicitly
55
/// by the compiler in many circumstances. This mechanism is called
6-
/// ['`Deref` coercion'][more]. In mutable contexts, [`DerefMut`] is used and
6+
/// ['`Deref` coercion'][coercion]. In mutable contexts, [`DerefMut`] is used and
77
/// mutable deref coercion similarly occurs.
88
///
9-
/// Deref coercion is a powerful language feature and has far-reaching
10-
/// implications for every type implementing `Deref`: the compiler will often
11-
/// implicitly call `Deref::deref`, as described [below][more]. For this reason,
12-
/// `Deref` should not be implemented unless all of the implications of coercion
13-
/// are understood and desired. Implementing `Deref` is most commonly desirable
14-
/// when a type
15-
///
16-
/// 1. should transparently behave like a contained value; and
17-
/// 2. does not have a rich set of methods in of itself, to avoid conflict or
18-
/// confusion with methods on the `Target` type.
19-
///
20-
/// For example, [`Box<T>`][box] is perhaps the canonical example for `Deref`:
21-
/// a `Box<T>` value **is** a `T` value that is heap-allocated, so deref
22-
/// coercion intuitively makes `Box<T>` act like `T`. `Box<T>`
23-
/// also has very few methods (though several associated functions), so it is
24-
/// unlikely that users will find conflict with methods on their target type.
25-
/// [`RefCell<T>`][refcell] also contains a value of `T`, but while it could
26-
/// implement `DerefMut`, it does not since there is a rich API of methods to
27-
/// explicitly manage the owned value: allowing deref coercion in this case
28-
/// would hide the explicit management and likely cause confusion.
29-
///
30-
/// Types that implement `Deref` and `DerefMut` are often called "smart
9+
/// **Warning:** Deref coercion is a powerful language feature which has
10+
/// far-reaching implications for every type that implements `Deref`. The
11+
/// compiler will silently insert calls to `Deref::deref`. For this reason, one
12+
/// should be careful about implementing `Deref` and only do so when deref
13+
/// coercion is desirable. See [below][implementing] for advice on when this is
14+
/// typeically desired or undesirable.
15+
///
16+
/// Types that implement `Deref` or `DerefMut` are often called "smart
3117
/// pointers" and the mechanism of deref coercion has been specifically designed
32-
/// to facilitate the pointer-like behaviour that name suggests. Very often, the
33-
/// only purpose of a "smart pointer" type is to change the ownership semantics
18+
/// to facilitate the pointer-like behaviour that name suggests. Often, the
19+
/// purpose of a "smart pointer" type is to change the ownership semantics
3420
/// of a contained value (for example, [`Rc`][rc] or [`Cow`][cow]) or the
3521
/// storage semantics of a contained value (for example, [`Box`][box]).
3622
///
37-
/// If deref coercion is not desirable, the [`AsRef`] or [`Borrow`][borrow]
38-
/// traits are alternatives which should be preferred in most cases.
39-
///
40-
/// # Fallibility
41-
///
42-
/// **This trait's method should never fail**. Deref coercion means the compiler
43-
/// will often implicitly call `Deref::deref`. Failure during
44-
/// dereferencing can be extremely confusing when `Deref` is invoked implicitly.
45-
///
46-
/// # More on `Deref` coercion
23+
/// # Deref coercion
4724
///
48-
/// If `T` implements `Deref<Target = U>`, and `x` is a value of type `T`, then:
25+
/// If `T` implements `Deref<Target = U>`, and `v` is a value of type `T`, then:
4926
///
50-
/// * In immutable contexts, `*x` (where `T` is neither a reference nor a raw pointer)
51-
/// is equivalent to `*Deref::deref(&x)`.
27+
/// * In immutable contexts, `*v` (where `T` is neither a reference nor a raw
28+
/// pointer) is equivalent to `*Deref::deref(&x)`.
5229
/// * Values of type `&T` are coerced to values of type `&U`
5330
/// * `T` implicitly implements all the methods of the type `U` which take the
5431
/// `&self` receiver.
5532
///
5633
/// For more details, visit [the chapter in *The Rust Programming Language*][book]
5734
/// as well as the reference sections on [the dereference operator][ref-deref-op],
58-
/// [method resolution] and [type coercions].
35+
/// [method resolution], and [type coercions].
36+
///
37+
/// # When to implement `Deref` or `DerefMut`
38+
///
39+
/// The same advice applies to both deref traits. In general, deref traits
40+
/// **should** be implemented if:
41+
///
42+
/// 1. a value of the type transparently behaves like a value of the target
43+
/// type;
44+
/// 1. the implementation of the deref function is cheap; and
45+
/// 1. users of the type will not be surprised by any deref coercion behaviour.
46+
///
47+
/// In general, deref traits **should not** be implemented if:
48+
///
49+
/// 1. the deref implementations could fail unexpectedly; or
50+
/// 1. the type has methods that are likely to collide with methods on the
51+
/// target type; or
52+
/// 1. committing to deref coercion as part of the public API is not desirable.
53+
///
54+
/// Note that there's a large difference between implementing deref traits
55+
/// generically over many target types, and doing so only for specific target
56+
/// types.
57+
///
58+
/// Generic implementations, such as for [`Box<T>`][box] (which is generic over
59+
/// every type) should be careful to few methods, since the target type
60+
/// is unknown and therefore every method could collide with one on the target
61+
/// type, causing confusion for users. `Box<T>` has few methods (though
62+
/// several associated functions), partly for this reason.
63+
///
64+
/// Specific implementations, such as for [`String`][string] (which only
65+
/// implements for `Target = str`) can have many methods, since avoiding
66+
/// collision is much easier. `String` and `str` both have many methods, and
67+
/// `String` additionally behaves as if it has every method of `str` because of
68+
/// deref coercion.
69+
///
70+
/// Consider also that deref coericion means that deref traits are a much larger
71+
/// part of a type's public API than any other trait as it is implicitly called
72+
/// by the compiler. Therefore, it is advisable to consider whether this is
73+
/// something you are comfortable supporting as a public API.
74+
///
75+
/// The [`AsRef`] and [`Borrow`][core::borrow::Borrow] traits have very similar
76+
/// signatures to `Deref`. It may be desirable to implement either or both of
77+
/// these, whether in addition to or rather than deref traits. See their
78+
/// documentation for details.
79+
///
80+
/// # Fallibility
81+
///
82+
/// **This trait's method should never unexpectedly fail**. Deref coercion means
83+
/// the compiler will often insert calls to `Deref::deref` implicitly. Failure
84+
/// during dereferencing can be extremely confusing when `Deref` is invoked
85+
/// implicitly. In the majority of uses it should be infallible, though it may
86+
/// be acceptable to panic if the type is misused through programmer error, for
87+
/// example.
5988
///
6089
/// [book]: ../../book/ch15-02-deref.html
61-
/// [more]: #more-on-deref-coercion
90+
/// [coercion]: #deref-coercion
91+
/// [implementing]: #when-to-implement-deref-or-derefmut
6292
/// [ref-deref-op]: ../../reference/expressions/operator-expr.html#the-dereference-operator
6393
/// [method resolution]: ../../reference/expressions/method-call-expr.html
6494
/// [type coercions]: ../../reference/type-coercions.html
65-
/// [box]: ../../std/boxed/struct.Box.html
66-
/// [refcell]: ../../std/cell/struct.RefCell.html
67-
/// [rc]: ../../std/rc/struct.Rc.html
68-
/// [cow]: ../../std/borrow/enum.Cow.html
69-
/// [borrow]: ../../std/borrow/trait.Borrow.html
95+
/// [box]: ../../alloc/boxed/struct.Box.html
96+
/// [string]: ../../alloc/string/struct.String.html
97+
/// [rc]: ../../alloc/rc/struct.Rc.html
98+
/// [cow]: ../../alloc/borrow/enum.Cow.html
99+
/// [borrow]: core::borrow::Borrow
70100
///
71101
/// # Examples
72102
///

0 commit comments

Comments
 (0)