Infered fields for partial borrowing

I've first posted this in the fields-in-traits repo since afaik that repo contains the most serious work towards partial borrowing, but maybe a comment here makes sense too.

In essence, there is seemingly no reason to name individual fields when doing partial borrowing. Instead "relative lifetimes" could more concisely express simultaneity requirements upon trait or inherent methods.

At a formal level, these relative lifetimes are associated lifetime constructors of the form:

impl Trait for Type {
    type 'a<'self> where 'self: 'a<'self> = { field1, field2 };

We do not require this syntax however since rustc could infer the assignment of fields to relative lifetimes. Actual syntax might resemble:

trait Trait {
    disjoint 'a, 'b, 'c;
    fn borrow_mut_a(&'a mut self) -> &'a mut A;
    fn borrow_mut_b(&'b mut 'a self) -> &'b mut B;
    fn borrow_mut_c(&'c+'a mut self) -> &'c mut C;

We'd need only some disjoint declaration for the relative lifetimes, as well as "algebra" of the relative lifetimes, which expresses what the methods may do.

There is no need to rush this into existence of course. Among the partial borrowing solutions, I do think field inference brings many benefits over named field approaches though, so imho named field based partial borrowing should probably not be too seriously considered.

As I said on github, named field approaches would typically require lifetimes too, which becomes really heavy notation. If we let rustc infer the fields, then we could focus upon methods, like what actually matters.

In fact, one could enter method names as abbreviations for their own lifetimes to recapture some of the lifetime elision:

pub trait Trait {
    disjoint foo,bar,'baz;
    fn foo(&self) -> &Foo;             // sugar for  fn foo(&'foo self) -> &'foo Foo;
    fn foo_mut(&'foo mut self) -> &'foo mut Foo;     // Explicitly reuses the lifetime defined for fn foo 
    fn bar(&mut self) -> &Bar;       // sugar for   fn bar(&'bar mut self) -> &'bar Bar;
    fn baz(&'foo mut 'baz self) -> ..      // Needs an explicit lifetime since it's doing something less common.

Again, I do not think partial borrowing should be prioritized per se, but I think field inference gives a preferable corner of that design space.

1 Like