@@ -38,24 +38,24 @@ However, this neglects the other aspect of `unsafe` that I described above: To
3838make the programmer aware that they are treading dangerous ground even when they
3939may not realize they are doing so.
4040
41- Using some more formal terminology, an ` unsafe ` block generally comes with a
42- proof * obligation * : The programmer has to ensure that this code is actually safe
43- to execute in the current context, because the compiler just trusts the
44- programmer to get this right. In contrast, ` unsafe fn ` represents an
45- * assumption * : As the author of this function, I make some assumptions that I
46- expect my callees to uphold. (In terms of
47- [ introduction and elimination forms of natural deduction ] ( https://en.wikipedia.org/wiki/Natural_deduction#Introduction_and_elimination ) ,
48- ` unsafe ` blocks are where you introduce, and ` unsafe fn ` is where you
49- eliminate.)
50-
51- Making ` unsafe fn ` also implicitly play the role of an ` unsafe ` block conflates
52- these two dual aspects of unsafety (one party making an assumption, another
53- party having the obligation to prove that assumption) . There is no reason to
54- believe that the assumption made by the ` unsafe fn ` is the same as the
55- obligation incurred by unsafe operations inside this function, and hence the
56- author of the ` unsafe fn ` should better carefully check that their assumptions
57- are sufficient to justify the unsafe operations they are performing. This is
58- what an ` unsafe ` block would indicate.
41+ In fact, this double role of ` unsafe ` in ` unsafe fn ` (making it both unsafe to
42+ call and enabling it to call other unsafe operations) conflates the two * dual *
43+ roles that ` unsafe ` plays in Rust. On the one hand, there are places that
44+ * define * a proof obligation, these make things " unsafe to call/do" (e.g., the
45+ language definition says that dereferencing a raw pointer requires it not to be
46+ dangling). On the other hand, there are places that * discharge * the proof
47+ obligation, these are "unsafe blocks of code" (e.g., unsafe code that
48+ dereferences a raw pointer has to locally argue why it cannot be dangling).
49+
50+ ` unsafe {} ` blocks are about * discharging * obligations, but ` unsafe fn ` are
51+ about * defining * obligations. The fact that the body of an ` unsafe fn ` is also
52+ implicitly treated like a block has made it hard to realize this duality
53+ [ even for experienced Rust developers ] [ unsafe-dual ] . (Completing the picture,
54+ ` unsafe Trait ` also defines an obligation, that is discharged by ` unsafe impl ` .
55+ Curiously, ` unsafe impl ` does * not * implicitly make all bodies of this ` impl `
56+ unsafe blocks, which is somewhat inconsistent with ` unsafe fn ` .)
57+
58+ [ unsafe-dual ] : https://github.com/rust-lang/rfcs/pull/2585#issuecomment-577852430
5959
6060# Guide-level explanation
6161[ guide-level-explanation ] : #guide-level-explanation
0 commit comments