From 37b8fc5baf128e80bd4424dce57a43d1e7f17630 Mon Sep 17 00:00:00 2001 From: Asensia <91839365+alicia-lyu@users.noreply.github.com> Date: Wed, 15 May 2024 20:10:26 -0500 Subject: [PATCH 1/3] Elaborate mutability design of unique pointer --- unique.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unique.md b/unique.md index d7e1378..a610ecb 100644 --- a/unique.md +++ b/unique.md @@ -57,6 +57,9 @@ fn foo() { As with primitive types in Rust, owning pointers and the data they point to are immutable by default. Unlike in C++, you can't have a mutable (unique) pointer to immutable data or vice versa. Mutability of the data follows from the pointer. +Correspondent with this design, mutability of the pointer means not only whether +that pointer can point to another memory address, but also whether the original +data may be modified. E.g., ```rust @@ -68,6 +71,7 @@ fn foo() { let mut x = Box::new(75); x = y; // OK, x is mutable. *x = 43; // OK, *x is mutable. + x = 76; // ERROR, type mismatch. } ``` From 13bb4b9b252f84f54b476271b5b1912b31ba3373 Mon Sep 17 00:00:00 2001 From: alicia-lyu Date: Wed, 15 May 2024 20:56:26 -0500 Subject: [PATCH 2/3] Clarify mutable reference --- borrowed.md | 65 ++++++++++++++++++++++++++--------------------------- unique.md | 4 +--- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/borrowed.md b/borrowed.md index f159f37..bda01f6 100644 --- a/borrowed.md +++ b/borrowed.md @@ -45,65 +45,64 @@ fn foo() { ``` Like values, borrowed references are immutable by default. You can also use -`&mut` to take a mutable reference, or to denote mutable reference types. -Mutable borrowed references are unique (you can only take a single mutable -reference to a value, and you can only have a mutable reference if there are no -immutable references). You can use a mutable reference where an immutable one is -wanted, but not vice versa. Putting all that together in an example: +`&mut` to take a mutable reference, or to denote mutable reference types. There are 3 levels of mutability here: + +- The data, defined by `let x = 5` or `let mut x = 5`. +- The reference, defined by `let xr = &x` or `let xr = &mut x`. +- The binding of the reference, defined by `let xr = &x` or `let mut xr2 = &x`. Its mutability defines whether the reference can be changed to point to another value. + +The reference can only be mutable if the data is mutable, as the mutability of the reference suggests whether the data can be modified through the reference. +This is similar to unique pointers. +The mutability of the binding of the reference is independent of the mutability of the reference itself or the data. +This is similar to C++ where pointers can be const (or not) independently of the data they point to. +This is in contrast to unique pointers, where the mutability of the pointer is linked to the mutability of the data. ```rust fn bar(x: &i32) { ... } -fn bar_mut(x: &mut i32) { ... } // &mut i32 is a reference to an i32 which - // can be mutated +fn bar_mut(x: &mut i32) { ... } // &mut i32 is a reference through which + // the i32 data can be mutated fn foo() { let x = 5; //let xr = &mut x; // Error - can't make a mutable reference to an // immutable variable - let xr = &x; // Ok (creates an immutable ref) + let mut xr = &x; // Ok (creates a mutable binding to an immutable ref) + let xr = &x; // Ok (creates an immutable binding to an immutable ref) + //xr = &mut y; // Error xr is immutable bar(xr); //bar_mut(xr); // Error - expects a mutable ref let mut x = 5; let xr = &x; // Ok (creates an immutable ref) - //*xr = 4; // Error - mutating immutable ref - //let xr = &mut x; // Error - there is already an immutable ref, so we - // can't make a mutable one - - let mut x = 5; let xr = &mut x; // Ok (creates a mutable ref) - *xr = 4; // Ok - //let xr2 = &x; // Error - there is already a mutable ref, so we - // can't make an immutable one - //let xr2 = &mut x; // Error - can only have one mutable ref at a time + *xr = 4; // Ok, x is mutable through xr + bar(xr); // Ok bar_mut(xr); // Ok } ``` -Note that the reference may be mutable (or not) independently of the mutableness -of the variable holding the reference. This is similar to C++ where pointers can -be const (or not) independently of the data they point to. This is in contrast -to unique pointers, where the mutableness of the pointer is linked to the -mutableness of the data. For example, +Mutable borrowed references are unique (you can only take a single mutable +reference to a value, and you can only have a mutable reference if there are no +immutable references). You can use a mutable reference where an immutable one is +wanted, but not vice versa. Putting all that together in an example: ```rust fn foo() { let mut x = 5; - let mut y = 6; - let xr = &mut x; - //xr = &mut y; // Error xr is immutable + let xr = &x; // Ok (creates an immutable ref) + //*xr = 4; // Error - mutating immutable ref + //let xr = &mut x; // Error - there is already an immutable ref, so we + // can't make a mutable one let mut x = 5; - let mut y = 6; - let mut xr = &mut x; - xr = &mut y; // Ok - - let x = 5; - let y = 6; - let mut xr = &x; - xr = &y; // Ok - xr is mut, even though the referenced data is not + let xr = &mut x; // Ok (creates a mutable ref) + *xr = 4; // Ok + //let xr2 = &x; // Error - there is already a mutable ref, so we + // can't make an immutable one + //let xr2 = &mut x; // Error - can only have one mutable ref at a time } + ``` If a mutable value is borrowed, it becomes immutable for the duration of the diff --git a/unique.md b/unique.md index a610ecb..a253980 100644 --- a/unique.md +++ b/unique.md @@ -57,9 +57,7 @@ fn foo() { As with primitive types in Rust, owning pointers and the data they point to are immutable by default. Unlike in C++, you can't have a mutable (unique) pointer to immutable data or vice versa. Mutability of the data follows from the pointer. -Correspondent with this design, mutability of the pointer means not only whether -that pointer can point to another memory address, but also whether the original -data may be modified. +Correspondent with this design, mutability of the pointer means not only whether that pointer can point to another memory address and **disown** the original data, but also whether the original data may be modified. E.g., ```rust From 06b785e35de4247ebf7d1bf91274117d3a790e88 Mon Sep 17 00:00:00 2001 From: alicia-lyu Date: Wed, 15 May 2024 21:05:58 -0500 Subject: [PATCH 3/3] Clarify borrowing scope --- borrowed.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/borrowed.md b/borrowed.md index bda01f6..c88ba0e 100644 --- a/borrowed.md +++ b/borrowed.md @@ -105,10 +105,13 @@ fn foo() { ``` -If a mutable value is borrowed, it becomes immutable for the duration of the -borrow. Once the borrowed pointer goes out of scope, the value can be mutated -again. This is in contrast to unique pointers, which once moved can never be -used again. For example, +If a mutable value is borrowed in the same scope, the original value (`x` above) becomes immutable while being borrowed (by `xr` above). +`x` can only be changed through `xr`. +If a mutable value is borrowed in a different scope, it becomes immutable while in that scope. +This is to ensure at any given time, there is only one mutable reference to a value, including the original value itself. + +Once the borrowed pointer goes out of scope, the value can be mutated again. +This is in contrast to unique pointers, which once moved can never be used again. For example, ```rust fn foo() {