I have an idea and I'd like to see what people think.
The idea is to add a Drop/Borrow like trait that provides hooks that allow you to inject code whenever a struct starts/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 serves for illustrative purposes. Making the lock implicit is generally 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 if you dereference to something that is Copy.
- It 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.
- As currently described, the &mut arguments require instances that implement it to always be declared mut, or be implicitly mut. &mut is the most flexible choice for the methods, but it does make it more annoying or more magic.
- There is a ton of code relying on & doing nothing but giving you a reference, so there would have to be an effort to be more explicit about what is actually guaranteed and any implementer would have be respect those guarantees and not do anything surprising (like panicking).
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.