exclusive reference -> unique reference
authorRalf Jung <post@ralfj.de>
Sun, 17 Jan 2016 14:20:09 +0000 (15:20 +0100)
committerRalf Jung <post@ralfj.de>
Sun, 17 Jan 2016 14:20:09 +0000 (15:20 +0100)
src/part04.rs
src/part05.rs
src/part06.rs
src/part12.rs
src/part14.rs
src/part15.rs
src/part16.rs
workspace/src/part04.rs

index fcfc8d92800cb2a54f592ff360a1b5d6e68dd11b..754ba625c9227453b145ddbfabf041ab8c1701ed 100644 (file)
@@ -97,14 +97,14 @@ fn shared_ref_demo() {
 //@ reference, Rust knows that it cannot mutate `v`. Hence the pointer into the buffer of `v`
 //@ that was created before calling `vec_min` remains valid.
 
 //@ reference, Rust knows that it cannot mutate `v`. Hence the pointer into the buffer of `v`
 //@ that was created before calling `vec_min` remains valid.
 
-// ## Exclusive, mutable references
-//@ There is a second way to borrow something, a second kind of reference: The *exclusive reference*. This is a reference that comes with the promise that
+// ## Unique, mutable references
+//@ There is a second way to borrow something, a second kind of reference: The *unique reference*. This is a reference that comes with the promise that
 //@ nobody else has *any kind of access* to the referee - there is no aliasing. As a consequence, it is always safe to mutate data through
 //@ nobody else has *any kind of access* to the referee - there is no aliasing. As a consequence, it is always safe to mutate data through
-//@ an exclusive reference, which is why they are usually called *mutable references*.
+//@ an unique reference, which is why they are usually called *mutable references*.
 
 //@ As an example, consider a function which increments every element of a vector by 1.
 //@ The type `&mut Vec<i32>` is the type of mutable references to `vec<i32>`. Because the reference is
 
 //@ As an example, consider a function which increments every element of a vector by 1.
 //@ The type `&mut Vec<i32>` is the type of mutable references to `vec<i32>`. Because the reference is
-//@ mutable, we can use a mutable iterator, providing mutable (exclusive) references to the elements.
+//@ mutable, we can use a mutable iterator, providing mutable (unique) references to the elements.
 fn vec_inc(v: &mut Vec<i32>) {
     for e in v.iter_mut() {
         *e += 1;
 fn vec_inc(v: &mut Vec<i32>) {
     for e in v.iter_mut() {
         *e += 1;
index 71d712ab9584c01b9b8b3922b1547e6ed414966d..784440cde25acc9093b681eacaa93c2880cc3af0 100644 (file)
@@ -124,7 +124,7 @@ enum Variant {
     Text(String),
 }
 //@ Now consider the following piece of code. Like above, `n` will be a reference to a part of `var`,
     Text(String),
 }
 //@ Now consider the following piece of code. Like above, `n` will be a reference to a part of `var`,
-//@ and since we wrote `ref mut`, the reference will be exclusive and mutable. In other words, right after the match, `ptr`
+//@ and since we wrote `ref mut`, the reference will be uniqie and mutable. In other words, right after the match, `ptr`
 //@ points to the number that's stored in `var`, where `var` is a `Number`. Remember that `_` means
 //@ "we don't care".
 fn work_on_variant(mut var: Variant, text: String) {
 //@ points to the number that's stored in `var`, where `var` is a `Number`. Remember that `_` means
 //@ "we don't care".
 fn work_on_variant(mut var: Variant, text: String) {
index 8f9a723bc2d02a42e045e24f01c86900ccdda0a0..9552eb5316224fa15e27bc216286ceb8b2afb7d7 100644 (file)
@@ -138,8 +138,8 @@ fn rust_foo(mut v: Vec<i32>) -> i32 {
 //@ When analyzing the code of `rust_foo`, Rust has to assign a lifetime to `first`. It will choose the scope
 //@ where `first` is valid, which is the entire rest of the function. Because `head` ties the lifetime of its
 //@ argument and return value together, this means that `&v` also has to borrow `v` for the entire duration of
 //@ When analyzing the code of `rust_foo`, Rust has to assign a lifetime to `first`. It will choose the scope
 //@ where `first` is valid, which is the entire rest of the function. Because `head` ties the lifetime of its
 //@ argument and return value together, this means that `&v` also has to borrow `v` for the entire duration of
-//@ the function `rust_foo`. So when we try to borrow `v` exclusively for `push`, Rust complains that the two references (the one
-//@ for `head`, and the one for `push`) overlap. Lucky us! Rust caught our mistake and made sure we don't crash the program.
+//@ the function `rust_foo`. So when we try to create a unique reference to `v` for `push`, Rust complains that the two references (the one
+//@ for `head`, and the one for `push`) overlap, so neither of them can be unique. Lucky us! Rust caught our mistake and made sure we don't crash the program.
 //@ 
 //@ So, to sum this up: Lifetimes enable Rust to reason about *how long* a reference is valid, how long ownership has been borrowed. We can thus
 //@ safely write functions like `head`, that return references into data they got as argument, and make sure they
 //@ 
 //@ So, to sum this up: Lifetimes enable Rust to reason about *how long* a reference is valid, how long ownership has been borrowed. We can thus
 //@ safely write functions like `head`, that return references into data they got as argument, and make sure they
index 8b04fb669ef23083556b7672b76306bdaf0ab881..34e994e10ca12750386d5e814cd053880550b05b 100644 (file)
@@ -89,7 +89,7 @@ fn demo_cell(c: &mut Callbacks) {
 //@ is a shared reference. However, it has to increment the reference count! Internally, `Rc` uses `Cell` for the count, such that it
 //@ can be updated during `clone`.
 //@ 
 //@ is a shared reference. However, it has to increment the reference count! Internally, `Rc` uses `Cell` for the count, such that it
 //@ can be updated during `clone`.
 //@ 
-//@ Putting it all together, the story around mutation and ownership through references looks as follows: There are *exclusive* references,
+//@ Putting it all together, the story around mutation and ownership through references looks as follows: There are *unique* references,
 //@ which - because of their exclusivity - are always safe to mutate through. And there are *shared* references, where the compiler cannot
 //@ generally promise that mutation is safe. However, if extra circumstances guarantee that mutation *is* safe, then it can happen even
 //@ through a sahred reference - as we saw with `Cell`.
 //@ which - because of their exclusivity - are always safe to mutate through. And there are *shared* references, where the compiler cannot
 //@ generally promise that mutation is safe. However, if extra circumstances guarantee that mutation *is* safe, then it can happen even
 //@ through a sahred reference - as we saw with `Cell`.
@@ -135,8 +135,8 @@ impl CallbacksMut {
             //@ the check will always succeed, as is actually entirely useless. However, this is not actually true. Several different `CallbacksMut` could share
             //@ a callback (as they were created with `clone`), and calling one callback here could trigger calling
             //@ all callbacks of the other `CallbacksMut`, which would end up calling the initial callback again. This issue of functions accidentally recursively calling
             //@ the check will always succeed, as is actually entirely useless. However, this is not actually true. Several different `CallbacksMut` could share
             //@ a callback (as they were created with `clone`), and calling one callback here could trigger calling
             //@ all callbacks of the other `CallbacksMut`, which would end up calling the initial callback again. This issue of functions accidentally recursively calling
-            //@ themselves is called *reentrancy*, and it can lead to subtle bugs. Here, it would mean that the closure runs twice, each time thinking it has an
-            //@ exclusive, mutable reference to its environment - so it may end up dereferencing a dangling pointer. Ouch! Lucky enough,
+            //@ themselves is called *reentrancy*, and it can lead to subtle bugs. Here, it would mean that the closure runs twice, each time thinking it has a
+            //@ unique, mutable reference to its environment - so it may end up dereferencing a dangling pointer. Ouch! Lucky enough,
             //@ Rust detects this at run-time and panics once we try to borrow the same environment again. I hope this also makes it
             //@ clear that there's absolutely no hope of Rust performing these checks statically, at compile-time: It would have to detect reentrancy!
             let mut closure = callback.borrow_mut();
             //@ Rust detects this at run-time and panics once we try to borrow the same environment again. I hope this also makes it
             //@ clear that there's absolutely no hope of Rust performing these checks statically, at compile-time: It would have to detect reentrancy!
             let mut closure = callback.borrow_mut();
index ae13e01af7d7b12c49e52469a28342da103c00b6..e16837ce352a6f10cde0595047c74c9898346b45 100644 (file)
@@ -38,7 +38,7 @@ pub fn sort<T: PartialOrd>(data: &mut [T]) {
     // Finally, we split our slice to sort the two halves. The nice part about slices is that splitting them is cheap:
     //@ They are just a pointer to a start address, and a length. We can thus get two pointers, one at the beginning and
     //@ one in the middle, and set the lengths appropriately such that they don't overlap. This is what `split_at_mut` does.
     // Finally, we split our slice to sort the two halves. The nice part about slices is that splitting them is cheap:
     //@ They are just a pointer to a start address, and a length. We can thus get two pointers, one at the beginning and
     //@ one in the middle, and set the lengths appropriately such that they don't overlap. This is what `split_at_mut` does.
-    //@ Since the two slices don't overlap, there is no aliasing and we can have both of them as exclusive, mutable slices.
+    //@ Since the two slices don't overlap, there is no aliasing and we can have both of them as unique, mutable slices.
     let (part1, part2) = data.split_at_mut(lpos);
     //@ The index operation can not only be used to address certain elements, it can also be used for *slicing*: Giving a range
     //@ of indices, and obtaining an appropriate part of the slice we started with. Here, we remove the last element from
     let (part1, part2) = data.split_at_mut(lpos);
     //@ The index operation can not only be used to address certain elements, it can also be used for *slicing*: Giving a range
     //@ of indices, and obtaining an appropriate part of the slice we started with. Here, we remove the last element from
index 47952d6995bb08a06b02602d61296a5b957209d3..79fd9b4fb843b80c59b92b871aa8f39633677558 100644 (file)
@@ -120,7 +120,7 @@ pub fn main() {
 //@ In part 13, we talked about types that are marked `Send` and thus can be moved to another thread. However, we did *not*
 //@ talk about the question whether a reference is `Send`. For `&mut T`, the answer is: It is `Send` whenever `T` is send.
 //@ `&mut` allows moving values back and forth, it is even possible to [`swap`](https://doc.rust-lang.org/stable/std/mem/fn.swap.html)
 //@ In part 13, we talked about types that are marked `Send` and thus can be moved to another thread. However, we did *not*
 //@ talk about the question whether a reference is `Send`. For `&mut T`, the answer is: It is `Send` whenever `T` is send.
 //@ `&mut` allows moving values back and forth, it is even possible to [`swap`](https://doc.rust-lang.org/stable/std/mem/fn.swap.html)
-//@ the contents of two mutable references. So in terms of concurrency, sending a mutable, exclusive reference is very much like
+//@ the contents of two mutable references. So in terms of concurrency, sending a mutable, unique reference is very much like
 //@ sending full ownership, in the sense that it can be used to move the object to another thread.
 //@ 
 //@ But what about `&T`, a shared reference? Without interior mutability, it would always be all-right to send such values.
 //@ sending full ownership, in the sense that it can be used to move the object to another thread.
 //@ 
 //@ But what about `&T`, a shared reference? Without interior mutability, it would always be all-right to send such values.
index 748e7d9651e445106a8b4d9690888e8878575352..efa48a5f52d2376b3af1b04be2bb096477144906 100644 (file)
@@ -123,7 +123,7 @@ impl<T> LinkedList<T> {
 //@ the data in the list lives at least as long as the iterator: If you drop the `T: 'a`, Rust will tell
 //@ you to add it back. And secondly, Rust will complain if `'a` is not actually used in the struct.
 //@ It doesn't know what it is supposed to do with that lifetime. So we use `PhantomData` again to tell
 //@ the data in the list lives at least as long as the iterator: If you drop the `T: 'a`, Rust will tell
 //@ you to add it back. And secondly, Rust will complain if `'a` is not actually used in the struct.
 //@ It doesn't know what it is supposed to do with that lifetime. So we use `PhantomData` again to tell
-//@ it that in terms of ownership, this type actually (exclusively) borrows a linked list. This has no
+//@ it that in terms of ownership, this type actually (uniquely) borrows a linked list. This has no
 //@ operational effect, but it means that Rust can deduce the intent we had when adding that
 //@ seemingly useless lifetime parameter.
 pub struct IterMut<'a, T> where T: 'a {
 //@ operational effect, but it means that Rust can deduce the intent we had when adding that
 //@ seemingly useless lifetime parameter.
 pub struct IterMut<'a, T> where T: 'a {
index 2a3a6488a7536e88c43395dfeb1a257224a83404..e0d522e00cb863d58d56168b33a132c74243b34a 100644 (file)
@@ -44,7 +44,7 @@ fn shared_ref_demo() {
     println!("The first element is: {}", *first);
 }
 
     println!("The first element is: {}", *first);
 }
 
-// ## Exclusive, mutable references
+// ## Unique, mutable references
 
 fn vec_inc(v: &mut Vec<i32>) {
     for e in v.iter_mut() {
 
 fn vec_inc(v: &mut Vec<i32>) {
     for e in v.iter_mut() {