book
book copied to clipboard
Explanation of unsafe traits could be improved
- I have searched open and closed issues and pull requests for duplicates, using these search terms:
- "unsafe trait"
- There is #3396, for which I bring new arguments.
- I have checked the latest
mainbranch to see if this has already been fixed, in this file:src/ch20-01-unsafe-rust.md
URL to the section(s) of the book with this problem:
https://github.com/rust-lang/book/blob/5f1b7abf2a582c3dcf14f66ddfcbef5f3b4b4033/src/ch20-01-unsafe-rust.md?plain=1#L442-L448
Description of the problem: I didn't understand unsafe traits from "Implementing an Unsafe Trait" in section 20.1. (The section on traits in the docs of the unsafe keyword helped.) I think it could be improved.
In particular, the sentence "A trait is unsafe when at least one of its methods has some invariant that the compiler can’t verify" is misleading for multiple reasons. (a) Sync and Send for example have no methods, so the premise is false, and yet they are unsafe traits. But to me the wording suggests it is a necessary condition. (b) In some sense a trait is unsafe because it was marked unsafe. Of course, there are the reasons for which this is usually done or should be done. But one might understand that there are conditions under which traits must be marked unsafe, and this seems to be part of the confusion in #3396. (c) Invariants of functions may be taken to mean preconditions (demands about arguments) or postconditions (guarantees about the return value). Although I believe the latter is meant, upon my first read I thought of the former. This makes some sense in the context of the discussion of unsafe functions that precedes. If preconditions are meant, a function that "has some invariant that the compiler can’t verify" is one which should be marked unsafe, which I believe @L4nterns also assumed in #3396. (d) Finally, what it tries to express (the purpose of unsafe traits) is in my opinion too complex to be expressed in a single sentence. Instead, it could be expanded to an explanation or omitted.
Suggested fix: The section on unsafe functions beautifully explains: "The unsafe keyword in this context indicates the function has requirements we need to uphold when we call this function, because Rust can’t guarantee we’ve met these requirements." Similarly, in the context of traits, it indicates that there are requirements we need to uphold when implementing the trait. I'd find it helpful to draw this parallel, as it helps justify the same keyword being used.
It might be a good idea to decide whether this section is intended to explain the purpose of unsafe traits or not. If so:
- My suggestion is to explain that a trait should be marked unsafe when the fact that a particular data structure implements it makes a guarantee about this data structure that the language cannot enforce, i.e. does not follow from the existence of a compiling
impl. (Most often this guarantee might be necessary in one of the trait's methods, but it can also be elsewhere, as e.g.SendandSyncshow.) - A code example to motivate unsafe traits could also facilitate understanding a lot. The example in the Rust standard library is good, or a trait
ZeroableorNegatablefor primitives that retain a valid state when their bit pattern is zeroed or negated, respectively, would also serve well as an illustration.
If not, a concise overview might read:
We can use
unsafeto implement an unsafe trait. Just like we can declare that a function is unsafe, we can declare that a trait is unsafe by adding theunsafekeyword beforetrait. Then, any implementation of that trait will need to be marked asunsafetoo, as shown in Listing 20-12.unsafe trait Foo …With
unsafebefore our trait declaration, we signal that implementing this trait erroneously might lead to memory safety issues. [Note that "erroneously" is ambiguous here in referring to the choice of type or the implementation of the trait's functions. Both can be a source of unsafety but we don't expand on that for conciseness.] Withunsafebefore an implementation of the trait, we promise that we have taken care to meet all of the trait's special safety requirements.As an example, recall the
SendandSyncmarker traits …For more on unsafe traits, refer to the documentation of the
unsafekeyword.