You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We can use `unsafe` to implement an unsafetrait.Atrait is unsafe when at
least one of its methods has some invariant that the compiler can’t verify.We
declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait`
and marking the implementation of the traitas `unsafe` too, as shown in
Listing 20-12.
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. Send and Sync show.)
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 Zeroable or Negatable for 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 unsafe to implement an unsafe trait. Just like we can declare that a function is unsafe, we can declare that a trait is unsafe by adding the unsafe keyword before trait. Then, any implementation of that trait will need to be marked as unsafe too, as shown in Listing 20-12.
unsafetraitFoo …
With unsafe before 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.] With unsafe before 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 Send and Sync marker traits …
main
branch 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:
book/src/ch20-01-unsafe-rust.md
Lines 442 to 448 in 5f1b7ab
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
andSend
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 markedunsafe
. 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 markedunsafe
, 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 markedunsafe
, 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:
impl
. (Most often this guarantee might be necessary in one of the trait's methods, but it can also be elsewhere, as e.g.Send
andSync
show.)Zeroable
orNegatable
for 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:
The text was updated successfully, but these errors were encountered: