Currently, if you have a Cell
, RefCell
, RWLock
or Mutex
, you can only access it via the various methods with either (or both) dynamic validity checks and restrictions on the operations that can occur. All of these are designed to be used in shared locations and all methods for interacting with them take &self
However, if you can get a &mut self
, then essentially none of these restrictions are required, since it’s known that nothing else can be interacting with the value and there’s no other borrows. That is we could provide &mut self
methods that yield references into Cell
s (and maybe atomic types) and direct access to the contents of Mutex
(etc.) without any synchronisation or dynamic borrow checks, in code:
impl<T> Cell<T> {
fn access_uniquely<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.value.get() }
}
}
impl<T> Mutex<T> {
fn access_uniquely<'a>(&'a mut self) -> &'a mut T {
unsafe { &mut *self.data.get() }
}
}
There’s at least two use-cases I can think of:
-
more flexible in-place initialisation of types: if you create a
Mutex<ComplexDataType>
you may wish to update parts of it progressively (or conditionally), but before it gets shared among threads, i.e. when&mut
access is still possible -
reading data out of a context type for a fork-join operation, i.e. currently one would write something like
let x = Mutex::new(0); let new_vector = { par_map(some_slice, ref |element| { // complicated stuff that occasionally touches the reference to `x` }) }; println!("{}", *x.lock());
but the last line will always succeed, as there’s no sharing at all. The change suggested in this post would make it possible for that operation to be free.
Does this sound crazy and/or desirable?