FnBorrow traits

I love Borrow and BorrowMut but algorithms frequently want to borrow a “view” into a data structure. It’d be very cool if closures could be used like mutable borrows, but they cannot because you cannot make FnOnce::Output dependent on the lifetime of the &mut self parameter of FnMut::call_mut.

Would this even be possible? Maybe:

pub trait FnOnce<Args> {
type Output<'fn>;
    extern "rust-call" fn call_once(self, args: Args) -> Self::Output<'static>;
pub trait FnMut<Args>: FnOnce<Args> {
    extern "rust-call" fn call_mut<'fn>(&'fn mut self, args: Args) -> Self::Output<'fn>;
pub trait Fn<Args>: FnMut<Args> {
    extern "rust-call" fn call<'fn>(&'fn self, args: Args) -> Self::Output<'fn>;

Is this doable? I.e. can FnOnce::call_once actually call FnMut::call_mut? I’d think no because consumed as self is not quite the same as 'static.

Instead, we might consider a second hierarchy, maybe named View*, but maybe FnBorrow* explains them better:

pub trait FnBorrowMut<Args<'borrow>> {
    type Output<'borrow>;
    extern "rust-call" fn borrow_mut<'borrow>(&'fn mut self, args: Args<'borrow>) -> Self::Output<'borrow>;
pub trait FnBorrow<Args<'borrow>>: FnBorrowMut<Args<'borrow>> {
    extern "rust-call" fn borrow<'borrow>(&'borrow self, args: Args<'borrow>) -> Self::Output<'borrow>;

These traits could be specified by the syntax

FnBorrow([Args]<'borrow>) -> [Output]<'borrow>
FnBorrowMut([Args]<'borrow>) -> [Output]<'borrow>

where [Args] and [Output] work like with Fn* traits, but now admit a special lifetime 'borrow to reference the lifetime of 'self.

We might create types satisfying these traits with the familiar |..| ... syntax, which now satisfies both Fn* and FnBorrow* traits when possible, but may only satisfy the FnBorrow* variant. Is this workable? I think so, but it’s tricky:

If v : &'a mut [T] then || v.iter_mut() satisfies FnBorrowMut() -> IterMut<'borrow,T>, but also satisfies FnOnce() -> IterMut<'a,T>. That’s okay, but we might want a borrow |..| ... syntax to distinguish, not sure.

1 Like

We might even magic a replacement for the Borrow traits

trait BorrowMut<T> = FnBorrowMut() -> &'borrow mut T;
trait Borrow<T> = FnBorrow() -> &'borrow T;

and permit ordinary values and referenced to be used with FnBorrow* traits.

There is an issue here that an BorrowMut<T> mutating T would receive considerable skepticism, but an FnBorrowMut() -> &'borrow mut T mutating the T looks less suspicious.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.