# Idea: Inline supertrait implementations

**URL:** <https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696>\
**Category:** language design\
**Created:** [April 17, 2023, 11:05pm UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696 "2023-04-17T23:05:00Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![moulins](https://avatars.discourse-cdn.com/v4/letter/m/d9b06d/32.png) [@moulins](https://internals.rust-lang.org/u/moulins)\
**Post date:** [April 17, 2023, 11:05pm UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/1 "2023-04-17T23:05:00Z")

</div>

In Rust, many traits come with 'subtraits' that refine and/or further constrain them. For example, in `core`: `Deref/DerefMut`, `PartialEq/PartialOrd`, `Eq/Ord`, etc... This allows maximum flexibility, but comes with several downsides:

- For implementors, this leads to boilerplate: one need to provide a separate `impl` block for each supertrait, which means repeated elements like generics parameters and `where` clauses. This can get pretty painful for traits at the top of complicated hierarchies, like `Ord`.
- For library authors, 'splitting off' a super-trait from a pre-existing trait is a breaking change, which can hinder API evolution.

Here's my solution for both of these issues: what if a trait and its supertrait(s) could be implemented together in a single `impl` block?

```rs
// This will implement both `Deref` and `DerefMut`.
impl DerefMut for Foo {
    // Declaring the supertrait's (`Deref`) items inline: all items must be present.
    // The supertrait must still be implemented separately if its items aren't provided here.
    type Target = Bar;
    fn deref(&self) -> &Bar { ... }

    fn deref_mut(&mut self) -> &mut Bar { ... }
}
```

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [April 18, 2023, 2:05am UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/2 "2023-04-18T02:05:07Z")

</div>

If this is to be made possible, I expect that it'll be necessary to mention both traits in the impl header, i.e.

```rust
impl Deref + DerefMut for Foo {

```

or that at a minimum this would require an opt in on the subtrait that it can be implicitly combined with the supertrait impl. Otherwise you break the current pattern of sealed traits via an empty supertrait impl which cannot be written outside of the source crate due to path visibility.

Pulling off trait items to a supertrait is breaking even if the `impl` block doesn't need to change, unfortunately, as you can name `Trait::item` directly, which would no longer be valid if the item is moved to a supertrait.

The fully general form combines some amount of "impl sets," partial `default impl`, and delegation/reexporting. But a specific targeted feature to enable extraction of supertraits would be useful separately from those, though it would still need to solve a significant subset of the problems involved in those.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [April 18, 2023, 6:19am UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/3 "2023-04-18T06:19:20Z")

</div>

A super-trait can add a new method with a default body, which today (sortof) isn't a breaking change, after [2845-supertrait-item-shadowing - The Rust RFC Book](https://rust-lang.github.io/rfcs/2845-supertrait-item-shadowing.html)

But that would start to be breaking again if one could implement multiple traits in the same block.

(Which is a shame, because I really do wish that splitting up traits could be made non-breaking.)

---

<div class="post-metadata">

**Author:** ![moulins](https://avatars.discourse-cdn.com/v4/letter/m/d9b06d/32.png) [@moulins](https://internals.rust-lang.org/u/moulins)\
**Post date:** [April 18, 2023, 11:07am UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/4 "2023-04-18T11:07:42Z")

</div>

> [@scottmcm](#):
>
> A super-trait can add a new method with a default body, which today (sortof) isn't a breaking change, after [2845-supertrait-item-shadowing - The Rust RFC Book](https://rust-lang.github.io/rfcs/2845-supertrait-item-shadowing.html)
> 
> But that would start to be breaking again if one could implement multiple traits in the same block.

I don't think this is a real blocker; the same shadowing rules could also apply in the `impl` block (i.e.: in case of ambiguities, always pick the most specific trait). This implies that instances of shadowing between a trait and its supertrait(s) will require going back to separate `impl` blocks, just like cases today where adding new inherent methods conflicting with downstream traits may require extra disambiguation at call-sites. In particular, one possible resolution could be:

- If an item in `Trait` shadows a non-default item in `Super`, require separate `impl` blocks;
- If an item in `Trait` shadows a default item in `Super`, interpret the name as only implementing the item of `Trait`, and emit a warn-by-default lint;
- If there are multiple supertraits declaring items of the same name, require separate `impl` blocks.

---

<div class="post-metadata">

**Author:** ![moulins](https://avatars.discourse-cdn.com/v4/letter/m/d9b06d/32.png) [@moulins](https://internals.rust-lang.org/u/moulins)\
**Post date:** [April 18, 2023, 1:20pm UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/5 "2023-04-18T13:20:03Z")

</div>

> [@CAD97](#):
>
> If this is to be made possible, I expect that it'll be necessary to mention both traits in the impl header, ...

IMHO this robs the feature of much of its interest (the possibility of splitting of a supertrait while staying semver-compatible); if some extra syntax is necessary, the opt-in on the subtrait would be my preference.

W.r.t. the sealed trait pattern, note that as long as the sealing trait doesn't have any items (including default ones) privacy isn't broken, as you need to mention at least one item of the supertrait to trigger the 'inline `impl`'.  
The proper way of dealing with `pub`-in-private traits would be to teach `rustc` about them, so that the 'inline `impl`' feature can be disabled for these supertraits; I don't know what the implications of such a change would be.

> Pulling off trait items to a supertrait is breaking even if the `impl` block doesn't need to change, unfortunately, as you can name `Trait::item` directly, which would no longer be valid if the item is moved to a supertrait.

Would there be any significant downsides in allowing `Trait::item` to work with items in supertraits? After all, you can already write things like `String::deref`, so allowing `DerefMut::deref` and `<String as DerefMut>::deref` doesn't seem such a big jump.

---

<div class="post-metadata">

**Author:** ![schuelermine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/schuelermine/32/10713_2.png) [@schuelermine](https://internals.rust-lang.org/u/schuelermine)\
**Post date:** [April 18, 2023, 9:39pm UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/6 "2023-04-18T21:39:09Z")

</div>

What if we required an annotation on the subtrait to allow merging `impl`s with the supertrait?

Possibilities include:

1. An attribute: `#[allow_merge(A)] trait B: A {}`
2. A keyword: `trait B: default A {}`

I feel the attribute is more flexible. By doing this, we can extend the attribute’s power to cover explicit merged trait implementations as suggested by @CAD97, but even outside of supertraits:

```rust
#[allow_merge(B, C)]
trait A {}

#[allow_merge(A, C)]
trait B {}

#[allow_merge(A, B)]
trait C {}

impl A + B + C for () {}

```

A `#[merge_group(ident)]` attribute might be more ergonomic, but it could be that we’d only want to encourage this for tight-knit deeply interrelated small groups of traits (anti-ergonomics à la raw pointers)

_Note_: this post was edited because I didn’t actually read the full thread so I suggested an idea that was already proposed.

---

<div class="post-metadata">

**Author:** ![dlight](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dlight/32/8462_2.png) [@dlight](https://internals.rust-lang.org/u/dlight)\
**Post date:** [April 21, 2023, 8:22am UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/7 "2023-04-21T08:22:09Z")

</div>

In case of ambiguity one could qualify the fns, like `fn Deref::deref(&self) -> &Bar` and `fn DerefMut::deref_mut(&mut self) -> &mut Bar` (if they had the same name)

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [July 20, 2023, 8:22am UTC](https://internals.rust-lang.org/t/idea-inline-supertrait-implementations/18696/8 "2023-07-20T08:22:19Z")

</div>

Closed on July 20, 2023, 8:22am UTC

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