@@ -38,24 +38,24 @@ However, this neglects the other aspect of `unsafe` that I described above: To
38
38
make the programmer aware that they are treading dangerous ground even when they
39
39
may not realize they are doing so.
40
40
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
59
59
60
60
# Guide-level explanation
61
61
[ guide-level-explanation ] : #guide-level-explanation
0 commit comments