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
.