# Same trait bounds for multiple type parameters

**URL:** <https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101>\
**Category:** traits working group\
**Created:** [February 22, 2021, 11:26am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101 "2021-02-22T11:26:09Z")\
**Posts on this page:** 13\
**Page:** 2

<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:** [February 22, 2021, 8:13pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/21 "2021-02-22T20:13:26Z")

</div>

> [@mankinskin](#):
>
> hm.. but I guess this only works for "derivable" traits.

No, it works for [anything you can implement on a tuple](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a8e833b3e21d0696482d0640e70aad7). That doesn't include `Fn` though.

---

<div class="post-metadata">

**Author:** ![atagunov](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/atagunov/32/5877_2.png) [@atagunov](https://internals.rust-lang.org/u/atagunov)\
**Post date:** [February 22, 2021, 8:30pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/22 "2021-02-22T20:30:47Z")

</div>

> [@quinedot](#):
>
> it works for [anything you can implement on a tuple](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7a8e833b3e21d0696482d0640e70aad7)

...but that doesn't help much does it? If you remove

```rust
impl MyTrait for (Foo, Bar) {}

```

from your example it stops compiling..

---

<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:** [February 22, 2021, 9:38pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/23 "2021-02-22T21:38:43Z")

</div>

It doesn't work for anything (unless you actually want to call the trait methods on the tuple), `rustc` isn't smart enough to do back-inference that `(A, B): Clone ⊢ A: Clone, B: Clone`

```rust
fn foo<A, B>(a: A, b: B) where (A, B): Clone {
    a.clone();
    b.clone();
}

fn main() {
    foo(1, 2);
}

```

```rust
error[E0599]: no method named `clone` found for type parameter `A` in the current scope
error[E0599]: no method named `clone` found for type parameter `B` in the current scope

```

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [February 24, 2021, 10:11am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/24 "2021-02-24T10:11:28Z")

</div>

> [@Nemo157](#):
>
> `rustc` isn't smart enough to do back-inference that `(A, B): Clone ⊢ A: Clone, B: Clone`

I guess it can't be made to, either, if we want to prevent adding impls from breaking code. Because traits are open, `A: Tr, B: Tr ⊢ (A, B): Tr` does not work in reverse.

---

<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:** [February 24, 2021, 7:42pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/25 "2021-02-24T19:42:06Z")

</div>

> [@jdahlstrom](#):
>
> I guess it can't be made to

Not with positive rules, certainly. But given the overlap/orphan rules, I wonder if we could allow it via negative rules -- I can't `impl Clone for (NotClone, NotClone)` (since tuples aren't `#[fundamental]`), so I'm not sure it's be possible to have a Clone tuple without the types inside being Clone.

But I know negative logic is complicated, so someone with better inference wizardry than I would be needed to say anything confidently.

---

<div class="post-metadata">

**Author:** ![mankinskin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mankinskin/32/6760_2.png) [@mankinskin](https://internals.rust-lang.org/u/mankinskin)\
**Post date:** [February 25, 2021, 8:41am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/26 "2021-02-25T08:41:57Z")

</div>

> [@jdahlstrom](#):
>
> I guess it can't be made to, either, if we want to prevent adding impls from breaking code.

Would we need to add any implementations? `(A, B): Clone` can only be true if `A` and `B` implement `Clone` [right?](https://doc.rust-lang.org/std/primitive.tuple.html#trait-implementations-1)

So the compiler could just infer that `A` and `B` are bound by `Clone`.

Edit: Ah, but that doesn't apply for all traits 😑

---

<div class="post-metadata">

**Author:** ![mankinskin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mankinskin/32/6760_2.png) [@mankinskin](https://internals.rust-lang.org/u/mankinskin)\
**Post date:** [February 25, 2021, 8:55am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/27 "2021-02-25T08:55:31Z")

</div>

So in that case I guess the current proposals are

- Local trait aliases

```rust
fn foo<'a, X, Y, Z, A: Tr<X>, B: Tr<Y>>(a: A, b: B)
    where Tr<T> = MyTrait<T> + Z + 'a

```

- trait bound application on multiple parameters

```rust
fn foo<'a, X, A: B: MyTrait<X> + 'a>(a: A, b: B)

```

- reusable trait bounds (name?)

```rust
fn my_fn<
    'a,
    I,
    A: Really<Item=I> + ALot<'a, I> + ToType,
    B: A, // <- B has all the same bounds as A
>(a: A, b: B)
{ ... }

```

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 25, 2021, 9:07am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/28 "2021-02-25T09:07:58Z")

</div>

> [@mankinskin](#):
>
> Local trait aliases
> 
> ```rust
> fn foo<'a, X, Y, Z, A: Tr<X>, B: Tr<Y>>(a: A, b: B)
> where Tr<T> = MyTrait<T> + Z + 'a
> 
> ```

This looks good, but I would mark it as a trait alias, otherwise it would conflict with equality constraints between types.. Something like:

```rust
fn foo<'a, X, Y, Z, A: Tr<X>, B: Tr<Y>>(a: A, b: B)
    where trait Tr<T> = MyTrait<T> + Z + 'a

```

> [@mankinskin](#):
>
> trait bound application on multiple parameters
> 
> ```rust
> fn foo<'a, X, A: B: MyTrait<X> + 'a>(a: A, b: B)
> 
> ```

IMO this is just ugly and confusing. It's also a great way to confuse the parser

---

<div class="post-metadata">

**Author:** ![mankinskin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mankinskin/32/6760_2.png) [@mankinskin](https://internals.rust-lang.org/u/mankinskin)\
**Post date:** [February 25, 2021, 9:16am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/29 "2021-02-25T09:16:28Z")

</div>

> [@SkiFire13](#):
>
> It's also a great way to confuse the parser

I don't know why that shouldn't be parsable. In my opinion it is pretty clear, but I can understand that it adds to the ambiguity of `:`

---

<div class="post-metadata">

**Author:** ![lordan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lordan/32/2107_2.png) [@lordan](https://internals.rust-lang.org/u/lordan)\
**Post date:** [February 25, 2021, 10:53am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/30 "2021-02-25T10:53:01Z")

</div>

> [@mankinskin](#):
>
> So in that case I guess the current proposals are
> 
> - Local trait aliases [...]
> - trait bound application on multiple parameters [...]

A third option would be back-references to already declared type parameters, e.g.:

```rust
fn my_fn<'a, I, A : Really<Item=I> + ALot<'a, I> + ToType, B : as A>(a: A, b: B)

```

That said, I'd personally prefer local trait aliases out of these options.

---

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://internals.rust-lang.org/u/2e71828)\
**Post date:** [February 25, 2021, 11:55am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/31 "2021-02-25T11:55:18Z")

</div>

> [@jdahlstrom](#):
>
> I mean, we don't have local type aliases in generic signatures either. (Should we?)

I’ve occasionally written things like this to approximate them:

```rust
trait Is { type Type; }
impl<T> Is for T { type Type = T; }

impl<A,B,TypeAlias> Something<TypeAlias> for B
where Some<Complicated<Struct<A>, B>>: Is<Type=TypeAlias>
{
    fn do_something(&self)->TypeAlias { ... }
}

```

---

<div class="post-metadata">

**Author:** ![ibraheemdev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ibraheemdev/32/13406_2.png) [@ibraheemdev](https://internals.rust-lang.org/u/ibraheemdev)\
**Post date:** [February 25, 2021, 1:54pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/32 "2021-02-25T13:54:20Z")

</div>

And just `A: B`

```rust
fn my_fn<
    'a,
    I,
    A: Really<Item=I> + ALot<'a, I> + ToType,
    B: A, // <- B has all the same bounds as A
>(a: A, b: B)
{ ... }

```

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [December 22, 2024, 4:55pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/33 "2024-12-22T16:55:10Z")

</div>

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

[Previous page](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101.md?page=1)
