If we're talking about owned values - sure. References are a different thing, they require lifetimes to be safe and sound, and so do views (especially shared ones with disjoint mutable accesses).
The issue here is whether we make the lifetimes (or rather, lifespans) explicit in the syntax or not. I argue that since they are for regular references, they should also be for partial ones.
this one means you almost have to read the type + lifetime backwards to know where x comes from
The .{...} syntax has the same issue, if you think about it. Go figure what ref group this particular field belongs to. Both variants suffer from this, which leads me to believe that it is either unavoidable or can be improved for both.
How does the compiler know which ref group is being borrowed? If it assumes both are, that is overly conservative and would not allow calling bar after foo (and vice versa).
While I'm at it, the immutable reference syntax &mut Foo.{&imm_grp, ...} is kinda clunky - I think mutability as opt in would be better:
True. I'd assumed they wouldn't differ because they're both from the same struct, but you're right. We probably want/need the ability to specify which group the return value comes from => Lifetimes in the field list => Having it before the type like you suggested probably makes more sense then.
fn foo(_: &{x, mut y} Foo) -> &u8 {} // Same as second line (lifetime elision)
fn foo<'a>(_: &'a {x, mut y} Foo) -> &'a u8 {} // return value can come from x or y
fn foo<'a, 'b>(_: &{'a x, 'b mut y} Foo) -> &'a u8 {} // return value comes from x
The more I think about having the fields first the more I like it: "I need a reference to the fields {x and mut y) of Foo".
To be pedantic - not fields but rather named lifespans (or by indices or place if it's a tuple-like fragmented reference). Analogous to the ref_groups mentioned earlier.
The original proposal included the syntax struct ref &('a, 'b, ...) Struct {...} because the lifetimes 'a, 'b, ... are like generic parameters within (...) braces instead of <...> to distinguish them from the syntax for generic parameters of structs and functions.
One could argue in favor of
fn foo(_: &<'_, '_ mut> Struct) {...}
Instead of
fn foo(_: &('_, '_) Struct) {...}
But for me it's simply not esthetic.
The problem with this "generic parameter" approach is, as was mentioned multiple times, the lack of named arguments. I hence propose we embrace the generic syntax fully and allow default lifespans, e.g.
struct ref &(~x='!, ~y='!, ~priv='!) Struct {...} //'
fn foo(_: &(~x='_) Struct) {...} // similar to `StructWithDefArg<T = i32>`
Now a new problem appears - what does &Foo represent? A regular reference with all lifespans being '_ or a fragmnted reference with the default lifespans being '!?
The only solution to this problem I can think of right now is requiring at least one lifespan to not have a default value. Or maybe allow lifespans to be '_ by default and if elision doesn't work demand the lifespan be specified.