You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the T-lang design meeting on 2024-04-24, a new syntax option was
raised: `use<..> impl Trait`.
While some people liked this, others did not, and no clear consensus
formed to change the main proposal in this RFC. Nevertheless, let's
discuss this as an alternative.
Copy file name to clipboardExpand all lines: text/3617-precise-capturing.md
+32Lines changed: 32 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -524,6 +524,8 @@ Picking an existing keyword allows for this syntax, including extensions to othe
524
524
525
525
By not putting the generic parameters on `impl<..>`, we reduce the risk of confusion that we are somehow introducing generic parameters here rather than using them.
526
526
527
+
We put `impl` before `use<..>` because `use<..>` is a property of the opaque type and we're *applying* the generic *parameters* as generic *arguments* to this opaque type. In `impl Trait` syntax, the `impl` keyword is the stand-in for the opaque type itself. Viewed this way, `impl use<..> Trait` maintains the following order, which is seen throughout Rust: *type*, *generic arguments*, *bounds*.
528
+
527
529
Using angle brackets, rather than parenthesis or square brackets, is consistent with other places in the language where type parameters are applied to a type.
528
530
529
531
At three letters, the `use` keyword is short enough that it doesn't feel too noisy or too much like a burden to use this, and it's parsimonious with other short keywords in Rust.
@@ -536,6 +538,36 @@ The original syntax proposal was `impl<..> Trait`. This has the benefit of bein
536
538
537
539
Decisive to some was that we may want this syntax to *scale* to other uses, most particularly to controlling the set of generic parameters and values that are captured by closure-like blocks. As we discuss in the future possibilities, it's easy to see how `use<..>` can scale to address this in a way that `impl<..> Trait` cannot.
538
540
541
+
### `use<..> impl Trait`
542
+
543
+
Putting the `use<..>` specifier *before* the `impl` keyword is potentially appealing as `use<..>` applies to the entire `impl Trait` opaque type rather than to just one of the bounds, and this ordering might better suggest that.
544
+
545
+
However, this visual association might also *prove too much*. That is, it could make the `use<..>` look more like a *binder* (like `for<..>`) rather than like a *property* of the opaque type.
546
+
547
+
The `use<..>` syntax *applies* the listed generic *parameters* as generic *arguments* to the opaque type. It's analogous, e.g., with the generic arguments here:
548
+
549
+
```rust
550
+
implTraitfor () {
551
+
typeOpaque<'t, T> =Concrete<'t, T>
552
+
// ^^^^^^^^|^^^^^
553
+
// Type | Generic Arguments
554
+
whereSelf: 'static;
555
+
// ^^^^^^^^^^^^^
556
+
// Bounds
557
+
}
558
+
```
559
+
560
+
Just as the above *applies*`<'t, T>` to `Concrete`, `use<..>` applies its arguments to the opaque type.
561
+
562
+
In the above example and throughout Rust, we observe the following order: *type*, *generic arguments* (applied to the type), *bounds*. In `impl Trait` syntax, the `impl` keyword is the stand-in for the opaque type itself. The `use<..>` specifier lists the generic arguments to be applied to that type. Then the bounds follow. Putting `use<..>` after `impl` is consistent with this rule, but the other way would be inconsistent.
563
+
564
+
This observation, that we're applying generic *arguments* to the opaque type and that the `impl` keyword is the stand-in for that type, is also a strong argument in favor of `impl<..> Trait` syntax. It's conceivable that we'll later, with more experience and consistently with [Stroustrup's Rule][], decide that we want to be more concise and adopt the `impl<..> Trait` syntax after all. One of the advantages of placing `use<..>` after `impl` is that there would be less visual and conceptual churn in later making that change.
565
+
566
+
Finally, there's one other practical advantage to placing `impl` before `use<..>`. If we were to do it the other way and place `use<..>` before `impl`, we would need to make a backward incompatible change to the `ty` macro matcher fragment specifier. This would require us to migrate this specifier according to our policy in [RFC 3531][]. This is something we could do, but it is a cost on us and on our users, and combined with the other good reasons that argue for `impl use<..> Trait` (or even `impl<..> Trait`), it doesn't seem a cost that's worth paying.
In some conceptions, the difference between `impl Trait + 'a + 'b` and `impl use<'a, 'b> Trait` is the difference between capturing the union of those lifetimes and capturing the intersection of them. This inspires syntax proposals such as `impl Trait & 't & T` or `impl Trait & ['t, T]` to express this intersection.
0 commit comments