Motivation
Many types contain functions like get and get_mut. This can be tolerated, but the creation of such functions tends to propagate when creating wrappers. It even creates overhead in rare cases.
No mutability qualifier
A new qualifier !mut is introduced to explicitly indicate the absence of mutability. The old syntax without its qualifier is preserved.
let n = 10;
let !mut n = 10;
let r = &n;
let r = &!mut n;
Generalized mutability qualifier
The new qualifier ?mut can only be used as a generalization parameter.
Syntax
The syntax !mut correlates with the already existing Negative impls, and ?mut with ?Sized.
There are 2 possible proposals for writing such a generic parameter:
fn foo<M: ?mut>(obj: &M Obj) -> &M i32 { ... }
fn foo<?mut M>(obj: &M Obj) -> &M i32 { ... }
Borrowing Rules
In the non-monomorphized &?mut function, references have both & and &mut constraints.
let M t = T::new();
let t: &M T = &M t;
// Not Copy/Clone, because it might be a unique reference:
// let _ = *&t; // Error
// Not writable of course because it might be shared reference
// *t = T::new(); // Error
// Cannot be mutably borrowed, because it might be shared
// let _: &mut T = &mut *t; // Error
// Cannot be immutably borrowed, because it might be unique
// let _: &T = &*t; // Error
No Duplicate Code
The main application is that there is no duplication of methods for obtaining members of type.
Similar methods should appear on most standard types, such as HashMap.
struct Foo {
field: i32
}
impl Foo {
fn bar<M: ?mut>(&M self) -> &M i32 {
&M self.field
}
}
Performance
Since functions with similar parameters must have the same binary representation, it is possible to take a reference to them, thus saving memory, if necessary to have mutable and immutable versions of the function:
struct Foo {
field: i32
}
impl Foo {
fn bar<M: ?mut>(&M self) -> &M i32 {
self.field
}
}
fn main() {
let f = Foo::bar;
let a = Foo { field: 9 };
println!("{}", f::<!mut>(a));
let mut b = Foo { field: 42 };
f::<mut>(b) += 5;
println!("{}", f::<!mut>(b));
}
What if the function has a different binary representation for the associated types in traits?
When searching for a trait implementation, implementations for mut and !mut will not be considered specializations of ?mut.