# Discussion: add grammar \`trait FooExt for Foo\`

**URL:** <https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937>\
**Category:** language design\
**Created:** [May 30, 2024, 2:53am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937 "2024-05-30T02:53:45Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [May 30, 2024, 2:53am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/1 "2024-05-30T02:53:45Z")

</div>

Currently, due to many reasons, we may define extend trait for some structs. For example, `CommandExt` for `Command` It is obvious that, `CommandExt` should only be implemented on `Command` struct, and thus the following code seems a little bit redundant:

```rust
trait CommandExt {
    // method definations;
}
impl CommandExt for Command {
    // impls of method definations
}

```

Should we add some new grammar, allow write those things in a block?

```rust
/// by default, we may marked CommandExt as a sealed trait
/// it might be crazy to impl FooExt for structs other than Foo
trait CommandExt for Command { 
    // impls of method definations
}

```

Since the trait `CommandExt` should not be used elsewhere, such defination seems more clearly.

Are there any disadvantages?

---

<div class="post-metadata">

**Author:** ![theemathas](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/theemathas/32/11817_2.png) [@theemathas](https://internals.rust-lang.org/u/theemathas)\
**Post date:** [May 30, 2024, 7:20am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/2 "2024-05-30T07:20:16Z")

</div>

This has been implemented as crates. No need for this to be built-in.

> **[extend](https://lib.rs/crates/extend)**
>
> Create extensions for types you don't own with extension traits but without the boilerplate

> **[easy-ext](https://lib.rs/crates/easy-ext)**
>
> An attribute macro for easily writing extension trait pattern

---

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [May 30, 2024, 7:49am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/3 "2024-05-30T07:49:32Z")

</div>

Firstly, both of the crate you mentioned (of coursely) using proc-macro, which might adding compile time by a little, and proc-macro are regarded `unsafe` since it could do anything.

Secondly, such crates lack of support by official, thus it may yield incompatitable code in the future version.

Lastly, there is a lot of things firstly been implemented as crates and later enter the std built-in, such as `hashbrown` and `lazy_cell`. "we have a crate thus we do not need this" is just a rude criterion.

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [May 30, 2024, 10:07am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/4 "2024-05-30T10:07:27Z")

</div>

The existence of a crate implementation is not sufficient to say that something shouldn't move into the toolchain; it just shows that experimentation has taken place outside the compiler, and gives you a way of assessing the idea against two criteria:

1. Has the design space been fully explored?
2. Is this useful enough to justify making everyone who works on the toolchain pay the cost of keeping it working?

The underlying reason for both of these criteria is that Rust has very strong backwards compatibility goals; if I have a crate that compiled and worked on Rust 1.x, then the expectation is that I can upgrade to any later version 1.y of the toolchain and have my crate compile and work.

This means that once something's in `std`, you should expect it to stay there forever (even [`core::mem::uninitialized`](https://doc.rust-lang.org/core/mem/fn.uninitialized.html) has stayed around, although there is no sound way to use it); that's why criteria 2 exists, because there's a price to keeping anything around. And criteria 1 exists because you can't remove parts of a stable feature; if you've designed it badly because you didn't explore the design space properly before committing, you're stuck with the bad design forever.

So, if you're pointing to existing crates as a counterargument, you need to point out what about those crates suggests that locking this API in place forever is going to hurt the Rust project more than the project gains from having that API built-in.

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [May 30, 2024, 10:41am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/5 "2024-05-30T10:41:27Z")

</div>

> [@Neutron3529](#):
>
> [Are] there any disadvantages?

I think the trait would need to be `Sealed` as well. Possibly even in a way that other types in the crate cannot `impl` it. What stops someone from writing:

```rust
impl CommandExt for MyStruct {
    // what goes here?
}

```

What methods are required? Defaulted? What parts should be `Self` or are `Command` regardless of what is doing `impl CommandExt`? These are hard questions whether `MyStruct` is in the same crate or external to it.

---

<div class="post-metadata">

**Author:** ![Neutron3529](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/neutron3529/32/6976_2.png) [@Neutron3529](https://internals.rust-lang.org/u/Neutron3529)\
**Post date:** [May 30, 2024, 11:30am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/6 "2024-05-30T11:30:24Z")

</div>

Thank you for your correction for my grammar mistake:)

`Sealed` might be a good idea, but I am unfamilar with it, thus I cannot say anything about that. Maybe I can add one more reason about such grammar:

```rust
trait CommandExt for Command // this could set `CommandExt` as a Sealed trait automatically

```

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [May 30, 2024, 12:40pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/7 "2024-05-30T12:40:53Z")

</div>

Dwelling on it a bit more, this just feels like an "`impl` for remote type" thing that happens to use `trait` to do what it is doing. Maybe there's a better way of declaring this? One new thing I see is that `impl Foo` is suddenly introducing a name rather than opening a block to enhance an already-declared name. Maybe a better syntax is `trait CommandExt for Type` where `Type` must be concrete (no generics or anything)?

The nice thing about being a trait is that there's something to `use` to bring the new methods into scope. Other than that, it really doesn't provide anything a trait normally does. `where T: CommandExt` is kind of pointless because only `Command` can implement it, so the genericity is excessive.

---

<div class="post-metadata">

**Author:** ![jjpe](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jjpe/32/9779_2.png) [@jjpe](https://internals.rust-lang.org/u/jjpe)\
**Post date:** [May 30, 2024, 2:07pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/8 "2024-05-30T14:07:38Z")

</div>

This is one of those things that is perfectly plausible to implement, and likely wouldn't even be too troublesome depending on the exact semantics.

I guess my question is mostly: are extension traits really used _so much_ that it deserves its own dedicated syntax? It's difficult to tell since the answer to that question is subject to e.g. perception bias.

The relevance is of the question is mostly that it seems reasonable to me to say that a language feature that is used once in a while but not all that much overall doesn't deserve an extended novelty budget (along either the syntactic or semantic dimensions), especially since the status quo, while slightly inelegant, isn't all that burdensome to begin with.

I'd rather have the rather limited engineering resources available to the Rust project as a whole be used for things like librarification of especially rustc, stabilization of full const generics etc. Those things already seem to take forever¹ without other features vying for the same attention.

Now of course if it turns out that extension traits are used **a lot** everywhere, there's a case to be made for extending the feature. But that would need to be shown first, I think.

¹ I'm speaking purely perceptually. I'm acutely aware that it's a slog going through all that, so it's not meant as a criticism in any way.

---

<div class="post-metadata">

**Author:** ![farnz](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/farnz/32/6587_2.png) [@farnz](https://internals.rust-lang.org/u/farnz)\
**Post date:** [May 30, 2024, 2:34pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/9 "2024-05-30T14:34:16Z")

</div>

> [@mathstuf](#):
>
> Dwelling on it a bit more, this just feels like an "`impl` for remote type" thing that happens to use `trait` to do what it is doing. Maybe there's a better way of declaring this? One new thing I see is that `impl Foo` is suddenly introducing a name rather than opening a block to enhance an already-declared name. Maybe a better syntax is `trait CommandExt for Type` where `Type` must be concrete (no generics or anything)?

Bikeshedding a little here, is this worth a new keyword (strict or weak)?

Something like

```rust
extension impl CommandExt for Command {
…
}

```

where the keyword `extension` is used to indicate that this is an extension implementation.

You can then `use thing::CommandExt;` to bring it into scope like an extension trait, possibly with the same semantics as `use thing::CommandExt as _;` to avoid unnecessary namespace pollution, but it's not a trait for the purposes of things like trait bounds, and you can't implement the same extension for multiple remote types.

---

<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 30, 2024, 8:26pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/10 "2024-05-30T20:26:15Z")

</div>

> [@farnz](#):
>
> You can then `use thing::CommandExt;` to bring it into scope like an extension trait, possibly with the same semantics as `use thing::CommandExt as _;` to avoid unnecessary namespace pollution

having the name of the extension trait visible is actually quite important for the niche scenario where two extension traits define the same method, so that they can be disambiguated via the `<T as SomeTrait>::method` syntax.

---

<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:** [May 31, 2024, 5:23pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/11 "2024-05-31T17:23:08Z")

</div>

> [@jjpe](#):
>
> are extension traits really used _so much_ that it deserves its own dedicated syntax?

I would argue that extension traits (that exist solely to be implemented by a single `impl` block) are underused specifically because of the extra weight that it takes to provide method syntax. Since function syntax is always _sufficient_, many potential users of extensions will just write functions instead outside of applications where method chaining and/or receiver autoref is highly impactful.

While `trait`s are the _mechanism_, what extensions actually are expressing is a way to write methods which avoids the problems that coherence exists to prevent. If you include "why can't I write an `impl` for this type" as well as usage of extension style traits, I think the utility threshold is easily passed.

And also FWIW, phrased in my preferred shape of "free methods" (detailed below) instead of sugar for "extension traits" the feature fits fairly well into the "make existing things just work in more cases" box and is thus a removal of a restriction (methods must always be associated functions) as much as it is an extension to language sugar.

> [@farnz](#):
>
> Bikeshedding a little here, is this worth a new keyword (strict or weak)?

I don't really think so; some combination of `trait` and `impl` is reasonable. At a language level this feature is combining the `trait` definition with the `impl` block and so that's what the syntax should say. Like how newtypes are just `struct` and not some additional keyword to say "this is a newtype style structure."

My personal favorite concept, however, is to just allow directly writing free methods, e.g.

```rust
fn f(self: &Command, …) -> … {
    …
}

```

then when `f` is in scope, it's available to method lookup on the `Command` type. That it's a method is determined by the use of a `self` parameter.

What is perhaps a bit interesting to ask in this case is what happens when you `use f as g`. It could then be available as `cmd.g()`, or it could behave like the trait version does\[1\] and still provide `cmd.f()`. Whether it supports `use f as _` to only be available to method lookup is also a question.

> [@binarycat](#):
>
> having the name of the extension trait visible is actually quite important for the niche scenario where two extension traits define the same method,

In the case where it's just a function instead of a trait, it's just `f(&cmd)` for disambiguated function call syntax instead of the more involved qualified UFCS.

And to that note, qualified UFCS is another potential option to address the underlying want here, e.g. allowing to write something like `cmd.(path::to::f)()` to call an item-path-lookup function with method syntax (and all that entails, e.g. autoref) instead of always needing to insert names into method lookup.

* * *

1. I haven't written nor looked for a proc macro that provides this syntax, but it's possible to polyfill by generating a trait with the same name as the free fn.

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)\
**Post date:** [May 31, 2024, 5:40pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/12 "2024-05-31T17:40:27Z")

</div>

> [@CAD97](#):
>
> My personal favorite concept, however, is to just allow directly writing free methods

It’s not my own personal favorite for a number of reasons, but the main one is that the name I would use for a method, in the context of a type or instance, isn’t the name I would use for a free function (which is still relevant because of universal call syntax). I’d end up just putting the free functions in a module named for the type anyway, and now we’ve reinvented extension traits but with less indication to rustc and rustdoc and _humans_ that that’s what they are.

---

<div class="post-metadata">

**Author:** ![quinedot](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/quinedot/32/7294_2.png) [@quinedot](https://internals.rust-lang.org/u/quinedot)\
**Post date:** [May 31, 2024, 11:11pm UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/13 "2024-05-31T23:11:25Z")

</div>

The restrictions (sealed) part could be phrased in terms of [RFC 3323.](https://rust-lang.github.io/rfcs/3323-restrictions.html)\[1\] Personally I think allowing the extension to be non-sealed is reasonable (think newtypes).

I definitely feel that is should have a direct desugaring to something you could write without the feature. I.e. you get an actual trait out: you have to import it to use it, it has a name you can import, you can name it in paths and qualified paths, you can bound on it, you don't have to bound on it if you know the concrete type, etc.

Then if you decide to update this extension in some way that hasn't grown an inline annotation yet, you can rewrite it like you had written an extension trait without this feature in the first place, and not break or have to change anything elsewhere.

* * *

Other loose thoughts...

- The implementation should be like an implementation for the named type IMO, and not defaulted methods (at least by default)

- Using `Self` is ambiguous sometimes... probably should mean "the implementor" outside of function bodies and other item definitions, and the target type within them

- How generics are declared needs sussing out

- What happens with `where` clauses needs sussing out

- Most of these things could just not be part of the MVP

* * *

1. though the OP seems to want something stronger than `impl(crate) trait` technically 

2. which don't support default values, so far anyway 

3. which don't support defaults either yet 

4. even when there is exactly one implementation, this unlocks things like shared opaque return types and a way to name otherwise unnameable things elsewhere 

5. which you want to be generic over 

6. thinking about the lack of non-supertrait elaboration here 

7. OTOH something something `Trait<X: Iterator> where Self: From<X::Item>` 

8. modulo trivially satisfied clauses

---

<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:** [June 1, 2024, 12:09am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/14 "2024-06-01T00:09:10Z")

</div>

I think a fundamental question that needs to be answered is whether the use case wants specifically to define an extension trait, or if it only wants to define a bundle of additional methods for some receiver type(s) that are imported separately and traits are just a convenient way that already exists to talk about such a bundle of functionality.

The reason I think answering this is important is that in the second case, a lot of questions now have fairly obvious answers or don't even really apply anymore.

- Only the primary impl block ever exists, so whether default function bodies are provided is irrelevant.
- How generics and generic bounds are captured for the bundled `trait` doesn't particularly matter either, since neither imports nor UFCS need to specify the generic list on the trait.
- Code isn't ever expected to be generic over or bound with the extension bundle, but instead to express the generic bound for which the extension is written.

A potential syntax that emphasizes the "impl first" understanding might be

```rust
impl<…> SelfTy<…> as trait TraitName
where …
{ … }

```

This isn't directly writable in Rust today, but this could be thought of as desugaring to something like

```rust
trait<…> TraitName
where Self: TraitName<Self = SelfTy<…>>, …
{ … }

```

When the `trait` isn't restricted to just the usage as an extension bundle, the extra syntax for separate trait and impl communicates meaningful information. I do agree it's desirable that an extension bundle be forwards compatible with evolving into a proper trait in the future, but the benefit of a more terse spelling for extension traits goes hand in hand with the more constrained application of extension traits as just an extension and not a trait for generalization of code.

---

<div class="post-metadata">

**Author:** ![georgebarwood](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/georgebarwood/32/8584_2.png) [@georgebarwood](https://internals.rust-lang.org/u/georgebarwood)\
**Post date:** [June 1, 2024, 1:58am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/15 "2024-06-01T01:58:37Z")

</div>

> [@Neutron3529](#):
>
> Are there any disadvantages?

Yes - Rust is already a large complicated hard to learn language, this would make the situation even worse.

---

<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:** [June 9, 2024, 4:37am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/16 "2024-06-09T04:37:30Z")

</div>

apon further reflection, i think there _should_ be some friction in defining extension crates, since their overuse can lead to several problems.

1. makes in unclear which crate defines a method
2. adding a new function to an extension trait is actually a breaking change, since it may overlap with another extension trait on the same type

these issues are actually perfectly analogous to the issues caused by wildcard imports.

---

<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:** [September 7, 2024, 4:37am UTC](https://internals.rust-lang.org/t/discussion-add-grammar-trait-fooext-for-foo/20937/17 "2024-09-07T04:37:54Z")

</div>

Closed on September 7, 2024, 4:37am UTC

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