I have an idea and I'd like to see what people think.
The idea is to add a Drop like trait that provides hooks that allow you to inject code whenever a struct starts being borrowed and stops being borrowed (only the first/last of overlapping borrows would trigger the call).
trait Borrows {
fn borrows_begin(&mut self) {}
fn borrows_end(&mut self) {}
}
The borrow checker should already have this information and I think it would be nice to be able to take advantage of it. My primary use case is for signaling to an underlying concurrent data structure that it's safe to modify its data without the need for the consumers to deal with an explicit guard.
Here's an "always" up-to-date lossy mpsc channel as an example:
See here.
In this example the borrows_begin and borrows_end in main would be inserted by the compiler. This allows the consumer to never have to worry about asking for updates (though they would have to be watchful for extended borrows). The example itself is a bit silly and comes with no guarantees of correctness but hopefully it serves for illustrative purposes. Making the lock implicit could be considered an anti-pattern, but it is convenient and in a non-blocking case where there are lots of short borrows, I
think it could provide a significant ergonomic win. This could be particularly relevant for garbage collection or caching schemes.
There are some other obvious downsides. It's easy to trigger calls inadvertently or more frequently than necessary, especially you dereference to something that is Copy. It also promotes a spooky action at distance that could be hard to understand and it does so in a much more prominent way than Drop does. Finally, as it's currently described, the &mut arguments require instances that implement it to always be declared mut, or be implicitly mut. I think &mut is the most flexible choice for the trait, but it does make it more annoying or more magic.
I'm still debating whether it would be a worthwhile addition and I'm sure there are many more tradeoffs (and hopefully other benefitting use cases!), but I haven't seen this idea explored before and given how uniquely rusty it is, I thought I would at least put it out there to see what other people think.