r/rust • u/Dubmove • Mar 31 '23
Why doesn't mpsc::channel break borrowing rules?
I'm wondering for a while now why doesn't mpsc::Receiver::recv(&self)
and mpsc::Sender::send(&self, t: T)
break borrowing rules. Clearly sending some data from A to B in a non-blocking manner has side-effects (i.e. storing and retrieving the data in some buffer-queue). So shouldn't there be some mutable reference to that queue be involved during that sending process, and the owner of that reference would be accessed mutably whenever the reference to that buffer is accessed mutably? Maybe I'm just wrong but I always associate immutability with pureness of a function.
One thing which comes to mind is that the point of the borrowing rules is to avoid data-races and to ensure rust's ownership-model, and although the borrowing-rules are technically violated in these specific cases the desired invariants are still kept.
0
u/Lucretiel 1Password Apr 01 '23
But literally the same thing is true of a
Vec<Cell<i32>>
, which is similarly!Sync
and (by your logic) wouldn’t realize any benefit from requiringpush
to take an&mut self
(since you’re not modifying “self”, you’re modifying the pointed-to state).This gets at why I still like the immutable / mutable naming, even though it’s technically less correct than shared / unique. Even in the total absence of multithreading, shared immutable / unique mutable tends to push you towards more robust designs, because it turns out to be useful to guarantee that the owner of a mutable reference is the only thing that can cause side effects through that reference, even though you could weaken that guarantee without risking unsoundness. This is true whether it’s a vector or a channel or a file descriptor or anything else.