# Idea: Trait+Impl Item for ergonomic extension traits

**URL:** <https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891>\
**Category:** language design\
**Created:** [August 14, 2020, 5:06am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891 "2020-08-14T05:06:22Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Havvy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/havvy/32/178_2.png) [@Havvy](https://internals.rust-lang.org/u/Havvy)\
**Post date:** [August 14, 2020, 5:06am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/1 "2020-08-14T05:06:22Z")

</div>

Occasionally one wants to create effectively inherent methods on foreign types for usage within their crate. When you do this, you have to define both a trait and an impl. All of the contents of the trait are just type signatures for the functions and then the impl contains the same type signatures but with an actual body. For example, say I want to add a method `foo()` to `Option<MyType>` to automatically create a new `MyType` if it's `None` and then call the method `foo()` on MyType. We have to write that out today as:

```rust
trait OptionMyTypeExt {
    fn foo(&mut self);
}

impl OptionMyTypeExt for Option<MyType> {
    fn foo(&mut self) {
        /* body of fn */
    }
}

```

Ideally I'd just like to write `impl Option<MyType>` but orphan rules get in the way, so we need the trait to have an item to have in scope for method resolution. But the trait being define separately doesn't actually help us. It duplicates the type signature so if we change it, we need to change it in two places. We never want to write a second implementation.

So, I propose a helper syntax where we just mash the trait and impl together:

```rust
trait OptionMyTypeExt impl Option<MyType> {
    fn foo(&mut self) {
        /* body of foo */
    }
}

```

This example creates the trait item and implementation item just like the original example. But, IMO, it has more benefits than just lowering the amount of duplication. By writing it like this, you give intent to the reader that this trait exists not to be implemented more than once, but just so it can be used. It also gives a single place for doc comments so you don't have to question whether to put them on the trait (where they're honestly more readable today in Rustdoc) away from the impl or next to the impl.

We could also choose to make the trait second class: We could just make it an item that when in scope, provides the methods for the method call operator. So you couldn't refer to it in a new impl or be generic over it. This would also disallow using generics on the trait itself, just the impl.

My only worry is that this would be yet another thing we'd have to teach about Rust and the gain in ergonomics would be marginal compared to that. But on the other hand, having an obvious almost-trivial way of creating inherent methods might open the doors to people using more of them. And if you just do the wrong thing and write the bare `impl`, the fix is just adding a keyword and a name. We could update the error index to show that and it'd be a pretty simple tool-assistable fix.

I'm pretty sure I could implement this in the compiler myself, and there are enough technical details that warrant a very detailed RFC, but before I think about that, I'd like to know the opinions of other Rustaceans if this is something I should even think about pursuing.

Before ending this, I'd like to just offer one more example. Itertool's defines a trait `Itertool` and has an implementation that is completely empty using default implementations in the trait. Their trait+impl could be combined using this proposal to be:

```rust
trait Itertool impl<T: Iterator> T { /*everything currently in the trait */ }

```

---

<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:** [August 14, 2020, 5:52am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/2 "2020-08-14T05:52:57Z")

</div>

A somewhat related idea:

> [@Idea: Simpler method-syntax private helpers](https://internals.rust-lang.org/t/idea-simpler-method-syntax-private-helpers/7460):
>
> Reading the [discussion about infix method calls](https://github.com/rust-lang/rfcs/issues/1579) made me wonder how much of the problem is that it’s just annoying to make a private helper function that uses method syntax. For example, suppose you wanted to write [Vec::sorted](https://internals.rust-lang.org/t/pre-rfc-ish-add-vec-sorted-and-friends/7454) for yourself. Today it looks something like this: trait VecEx { fn sorted(self) -\> Self; } impl\<T: Ord\> VecEx for Vec\<T\> { fn sorted(mut self) -\> Self { self.sort(); self } } What if, instead, you could just write this? (Note the self.) fn …

I might argue that for something as big as `Itertools`, the extra `impl Itertools for impl Iterator {}` line isn't a big deal. But for small, one-off things for local use, even the `trait` part is a pain, so I'd like to get right of that too.

---

<div class="post-metadata">

**Author:** ![Havvy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/havvy/32/178_2.png) [@Havvy](https://internals.rust-lang.org/u/Havvy)\
**Post date:** [August 14, 2020, 6:23am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/3 "2020-08-14T06:23:38Z")

</div>

Hmm, seems the procedural macro already exists, albeit with different syntax: [https://docs.rs/crate/extension-trait/0.2.1](https://docs.rs/crate/extension-trait/0.2.1)

I'm not a fan of your desugaring because it doesn't let you group multiple associated items together or allow for things other than functions. It feels very specialized to the problem being solved.

For extremely local usage, we could make it so that you don't actually have to name the trait. Just leave it as an `_`: `trait _ impl Vec<T> {}`.

Edit: Oh, I see what you mean that the whole `impl` boilerplate is too much for local use. In that case, we could extend it to:

```rust
trait _ fn extension(ForeignType, /* other args */) {}

```

I don't know if eliminating that much boilerplate is worth it.

---

<div class="post-metadata">

**Author:** ![alexheretic](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/alexheretic/32/4800_2.png) [@alexheretic](https://internals.rust-lang.org/u/alexheretic)\
**Post date:** [August 14, 2020, 10:02am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/4 "2020-08-14T10:02:35Z")

</div>

I would support a more ergonomic way of writing an extension method. So thanks for starting the conversation!

Using some sort of `trait` syntax shortcut seems natural as that's how we do it currently. But I had some other thoughts on this topic a little while ago, though I lacked the motivation to drive a conversation on it here. I may as well propose them now.

## Example `is_alex`

First a simple motivating example. I can currently write a function in a module.

```rust
// foo.rs
pub(crate) fn is_alex(s: &str) -> bool {
    s.to_ascii_lowercase() == "alex"
}

```

This imports and is used quite naturally.

```rust
// main.rs
mod foo;
use foo::is_alex;

async fn is_alex_best_at_examples() -> Result<bool, reqwest::Error> {
    assert!(is_alex("Alex"));
    assert!(!is_alex("Barry"));

    let alex_is_best = is_alex(
        &reqwest::get("https://www.example.com/best-person")
            .await?
            .text()
            .await?,
    );

    Ok(alex_is_best)
}

```

But in this case I'd prefer to call this function in a fluent style `foo.is_alex()`.

## How to do this currently & why it isn't ideal for this use case

This _can_ be done.

```rust
// foo.rs
pub trait IsAlex {
    fn is_alex(&self) -> bool;
}

impl<S> IsAlex for S where S: AsRef<str> {
    fn is_alex(&self) -> bool {
        self.as_ref().to_ascii_lowercase() == "alex"
    }
}

```

To import it though I need to use the trait name.

```rust
// main.rs
mod foo;
use foo::IsAlex;
...

```

This does already work which is a big plus. However I like less that:

- I import using my trait name, when I only really care about the one function.
- It's more syntax to define compared to plain function.

For me it's just about painful enough that I may prefer plain functions in many cases where the usage would be better as fluent style.

## Idea: `self` implies extension method

How about my `foo` module looking like this?

```rust
// foo.rs
pub(crate) fn is_alex(self: &str) -> bool {
    self.to_ascii_lowercase() == "alex"
}

```

The `self` usage, which wouldn't compile currently, indicates this is an extension method called with `.is_alex()` but is otherwise identical to the normal function above.

The function imports in the same natural way.

```rust
// main.rs
mod foo;
use foo::is_alex;

async fn is_alex_best_at_examples() -> Result<bool, reqwest::Error> {
    assert!("Alex".is_alex());
    assert!(!"Barry".is_alex());

    let alex_is_best = reqwest::get("https://www.example.com/best-person")
        .await?
        .text()
        .await?
        .is_alex();

    Ok(alex_is_best)
}

```

Because we use very similar `fn` syntax we get:

- Strong consistency with plain function, importing, generics usage etc.
- `self` is fairly self-explanatory & `self: Type` usage already exists (`self: Box<Self>`).

So I think it has a low weirdness cost.

### Issues

- Trait / extension import collision. Should be an error?
- Extra language complexity.

### Related

- [Kotlin extension functions](https://kotlinlang.org/docs/reference/extensions.html)
- [C# extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods)

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [August 14, 2020, 10:21am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/5 "2020-08-14T10:21:04Z")

</div>

> [@alexheretic](#):
>
> Idea: `self` implies extension method

Ouch. That breaks a fundamental current behavior, that argument names _in free functions_ are part of the implementation and not the interface, and that changing argument names don't cause breakage. Doing this outside method context is very confusing.

* * *

Apart from that, I don't buy the inconvenience argument (as most of you might be used to it) – if the extension trait is really a small one-off trait, then typing up a function signature shouldn't be the reason for adding more syntax, because you can literally just copy and paste it.

As to indicating that a trait is an extension trait, naming convention (`FooExt`), or documentation, or both can be used.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [August 14, 2020, 10:23am UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/6 "2020-08-14T10:23:23Z")

</div>

> [@H2CO3](#):
>
> That breaks a fundamental current behavior, that argument names _in free functions_ are part of the implementation and not the interface, and that changing argument names don't cause breakage.

Given that `self` is not allowed in free functions at all currently, and is a keyword-like identifier that is known to change behaviour, and has exactly this current behaviour in all `fn` signatures that you can use it in, this doesn't seem like a big deal.

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [August 14, 2020, 12:45pm UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/7 "2020-08-14T12:45:33Z")

</div>

Maybe this is a slightly asinine response, but seeing as this can be accomplished with a simple macro (e.g. [https://docs.rs/extend/0.1.2/extend/](https://docs.rs/extend/0.1.2/extend/)), I think this is the kind of thing best left to a library?

I'm also semi-not-a-fan of extension methods, unless we get a `$expr.$path($exprs)` production, so that folks can write

```rust
foo.OptionMyTypeExt::foo();

```

to disambiguate without having to deal with UFCS and how it totally breaks the niceness of chaining.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [August 14, 2020, 12:51pm UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/8 "2020-08-14T12:51:52Z")

</div>

> [@alexheretic](#):
>
> ## Idea: `self` implies extension method
> 
> How about my `foo` module looking like this?
> 
> ```rust
> // foo.rs
> pub(crate) fn is_alex(self: &str) -> bool {
> self.to_ascii_lowercase() == "alex"
> }
> 
> ```

That's something neat; I think the best first step is to already provide that functionality as a classic library crate through a procedural macro:

```rust
mod example {
    #[extension_method]
    pub(crate)
    fn is_alex<'__> (self: &'__ str) -> bool
    {
        self.eq_ignore_ascii_case("alex")
    }
}

fn main ()
{
    use core::ops::Not;
    use example::is_alex;
    assert!("Alex".is_alex());
    assert!("Lex Luthor".is_alex().not());
}

```

- [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=edf4a15bfed489c7dfcaca979c3d261c)

---

<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:** [November 12, 2020, 12:51pm UTC](https://internals.rust-lang.org/t/idea-trait-impl-item-for-ergonomic-extension-traits/12891/9 "2020-11-12T12:51:52Z")

</div>

Closed on November 12, 2020, 12:51pm UTC

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