# Generalized Partial Borrows

**URL:** <https://internals.rust-lang.org/t/generalized-partial-borrows/22870>\
**Category:** language design\
**Created:** [May 6, 2025, 4:02pm UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870 "2025-05-06T16:02:37Z")\
**Posts on this page:** 7\
**Page:** 2

<div class="post-metadata">

**Author:** ![a\_cool\_nickname](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/a_cool_nickname/32/13219_2.png) [@a\_cool\_nickname](https://internals.rust-lang.org/u/a_cool_nickname)\
**Post date:** [May 7, 2025, 2:07pm UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/21 "2025-05-07T14:07:31Z")

</div>

> [@DragonDev1906](#):
>
> Tuples are weird in both representations/syntaxes:
> 
> ```rust
> fn foo(value: &(u8, u8, u8).{1}) {}
> fn foo(value: &{1} (u8, u8, u8)) {}
> 
> ```

In the original proposal I specifically talked about this:

```rust
fn foo(value: &(u8, '! u8, '! u8)) {}

```

Or, for clarity:

```rust
fn foo(value: &('_ u8, '! u8, '! u8)) {}

```

I think you misunderstood me - I was talking about tuple references, not references to tuples.

Tuple reference:

```rust
&('x, '!, '!) Foo // equivalent to `&{0: 'x, ..} Foo`
&(, '!, '!) Foo // equivalent to `&{0, ..} Foo` and `&('_, '!, '!) Foo` and `&('_, ..) Foo`

```

V.s. reference to tuple:

```rust
&('x, '!, '!) (T, U, V) // equivalent to `&('x, ..) (u8, u8, u8)` and `&('x T, '! U, '! V)`

```

---

<div class="post-metadata">

**Author:** ![a\_cool\_nickname](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/a_cool_nickname/32/13219_2.png) [@a\_cool\_nickname](https://internals.rust-lang.org/u/a_cool_nickname)\
**Post date:** [May 7, 2025, 2:25pm UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/22 "2025-05-07T14:25:59Z")

</div>

> [@DragonDev1906](#):
>
> Personally I still think `Foo` is more relevant/important (in regards to what you can give the function) than which fields of foo are relevant (this one means you almost have to read the type + lifetime backwards to know where x comes from)

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.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [May 8, 2025, 2:16am UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/23 "2025-05-08T02:16:05Z")

</div>

I think a soft keyword would actually be fine here, since struct field names are just identifiers and not expressions or patterns.

---

<div class="post-metadata">

**Author:** ![a\_cool\_nickname](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/a_cool_nickname/32/13219_2.png) [@a\_cool\_nickname](https://internals.rust-lang.org/u/a_cool_nickname)\
**Post date:** [May 8, 2025, 4:29am UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/24 "2025-05-08T04:29:54Z")

</div>

> [@DragonDev1906](#):
>
> Aren't non-borrowed variables (`let x: MyStruct`) also just a view (think about padding)? You could thus probably argue that all struct definitions already define a view (same for enums) and thus all types are already a view, regardless of the existence of lifetimes or borrowing.

Take the following function:

```rust
fn foo(val: &mut Foo.{grp1, &grp2}) -> &bool {...}

fn bar(val: &mut Foo.{&grp1, grp2}) -> &u64 {...}

```

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:

```rust
fn copy_y_get_x_mut(val: &Struct.{mut x, y}) {...} // instead of `&mut Struct.{x, &y}`

```

---

<div class="post-metadata">

**Author:** ![DragonDev1906](https://avatars.discourse-cdn.com/v4/letter/d/e68b1a/32.png) [@DragonDev1906](https://internals.rust-lang.org/u/DragonDev1906)\
**Post date:** [May 8, 2025, 7:55am UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/25 "2025-05-08T07:55:22Z")

</div>

> [@a\_cool\_nickname](#):
>
> 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).

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.

```rust
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".

---

<div class="post-metadata">

**Author:** ![a\_cool\_nickname](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/a_cool_nickname/32/13219_2.png) [@a\_cool\_nickname](https://internals.rust-lang.org/u/a_cool_nickname)\
**Post date:** [May 8, 2025, 8:30am UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/26 "2025-05-08T08:30:17Z")

</div>

> [@DragonDev1906](#):
>
> 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_group`s mentioned earlier.

---

<div class="post-metadata">

**Author:** ![a\_cool\_nickname](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/a_cool_nickname/32/13219_2.png) [@a\_cool\_nickname](https://internals.rust-lang.org/u/a_cool_nickname)\
**Post date:** [May 8, 2025, 3:11pm UTC](https://internals.rust-lang.org/t/generalized-partial-borrows/22870/27 "2025-05-08T15:11:28Z")

</div>

> [@DragonDev1906](#):
>
> I wonder if there is any situation where you wouldn't want `, ..` here.

I think I have a solution:

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

```rust
fn foo(_: &<'_, '_ mut> Struct) {...}

```

Instead of

```rust
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.

```rust
struct ref &(~x='!, ~y='!, ~priv='!) Struct {...} //'

fn foo(_: &(~x='_) Struct) {...} // similar to `StructWithDefArg<T = i32>`

```

Or

```rust
struct ref &<~x='!, ~y='!, ~priv='!> Struct {...} //'

fn foo(_: &<~x='_> Struct) {...} 

```

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.

[Previous page](https://internals.rust-lang.org/t/generalized-partial-borrows/22870.md?page=1)
