# 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:** 20\
**Page:** 1

<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 22, 2021, 11:26am UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/1 "2021-02-22T11:26:09Z")

</div>

(reposting [Same trait bounds for multiple type parameters - #3 by mankinskin - help - The Rust Programming Language Forum](https://users.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/55918/3))

Hi there, I just came across this situation:

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

```

And was wondering if I there is a syntax (or an RFC for it) to define trait bounds on multiple type parameters, something like:

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

```

The only way I would know to mitigate this is by implementing a utility trait:

```rust
trait ReallyALotToType<'a, I>: Really<Item=I> + ALot<'a, I> + ToType {}
impl<'a, I, T: Really<Item=I> + ALot<'a, I> + ToType> ReallyALotToType<'a, I> for T {}

```

```rust
fn my_fn<
    'a,
    I,
    A: ReallyALotToType<'a, I>,
    B: ReallyALotToType<'a, I>,
>(a: A, b: B)
{ ... }

```

But that doesn't scale as well as the first solution, especially when there are many type parameters involved in the trait. Also it introduces a lot of cognitive clutter, you have to think of a name for the trait, you have to implement it, all only really to tell the compiler something very simple: "These type parameters have the same trait bounds!"

The syntax could be debated, of course `,` would be the nicest to separate type parameter names before a trait bound, but that is already taken in this context. Other versions I could think of:

- `A : B: Trait,`
- `A | B: Trait,`
- `A B: Trait,`
- `(A, B): Trait,`

Maybe this could be taken even further and the type parameter context could allow for incremental definitions of trait bounds, i.e. type parameter names can be repeated to add new bounds, so that this would be possible: `<(A, B): Trait, A: Debug>`

---

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

</div>

> [@mankinskin](#):
>
> Other versions I could think of:
> 
> - `A : B: Trait,`
> - `A | B: Trait,`
> - `A B: Trait,`
> - `(A, B): Trait,`

- `A & B` is surprising, because it looks like an intersection type. It reads like "the intersection of type A and B satisfies the bounds on the RHS", but that's not what it means.
- `A : B` is surprising, because `:` is used in two completely different meanings in two immediately neighboring contexts.
- `A | B` is also surprising, because it means alternation ("or") in every other situation (even in the `regex` crate), not conjunction.
- `(A, B)` doesn't work because [it already means a tuple](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c9f211bbadd47673d5770c79a810f150).
- Simple juxtaposition `A B` _could_ technically work, but it's ugly, as in "unusual for the Rust programmer's eye". I don't know of any other place in Rust-the-core-language where items aren't separated by anything. (People do that in quick one-off private macros out of laziness, but the trait system is so central, it deserves much more than that.)

For conjunction of trait bounds, `+` is used, but that would _also_ mean overloading the `+` symbol even more, so I don't really like that, either.

---

<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 22, 2021, 1:34pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/3 "2021-02-22T13:34:41Z")

</div>

I've come across situations where this would be really helpful as well. What about just being able to write `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:** ![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 22, 2021, 1:37pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/4 "2021-02-22T13:37:20Z")

</div>

`A : B: Trait` does look weird, although I would not say the meaning is all that different, if you think of it as "is bounded by". This would even make sense with respect to `impl Trait`, which are traits in type argument position.

> [@ibraheemdev](#):
>
> What about just being able to write `A: B` ?

This is an even better idea! This would also easily allow for `A: B + SomethingElse`.

---

<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:** [February 22, 2021, 1:46pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/5 "2021-02-22T13:46:48Z")

</div>

> [@mankinskin](#):
>
> if you think of it as "is bounded by"

But that's exactly the problem: it does _not_ mean "is bounded by" here. It means "and". However, "bounded by" approximately means subtyping, so `A: B` in a type context would basically amount to saying that "type A should inherit from type B", if only Rust supported inheritance. However, there's no such subtyping relationship between types proper; types can only be bounded by traits, not other types.

Anyway, wouldn't [trait aliases](https://github.com/rust-lang/rfcs/blob/master/text/1733-trait-alias.md) solve this problem without the need for even more additional syntax? If you were allowed to write `trait Long = Really<Item=I> + ALot<'a, I> + ToType`, then you could just say `A: Long, B: Long` instead.

(And at that point, I don't think this proposal would stand because it wouldn't really simplify enough for it to be worth a language change.)

---

<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, 1:50pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/6 "2021-02-22T13:50:25Z")

</div>

Would it be easier to carve a syntax for this in `where` clause?

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

```

Of course this isn't that nice to parse either... Maybe something else after `where`?...

---

<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 22, 2021, 2:15pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/7 "2021-02-22T14:15:01Z")

</div>

> [@H2CO3](#):
>
> If you were allowed to write `trait Long = Really<Item=I> + ALot<'a, I> + ToType` , then you could just say `A: Long, B: Long` instead.

This does help, but for traits with many type parameters it would still not be ideal... `trait Long<T, C, E, U>`, especially when there are more than two type parameters to be bounded. It might seem like an edge case, but I think this needs to be considered to enable more of rust's generic programming capabilities. I think a big factor that is holding us back here is the syntax.

> [@H2CO3](#):
>
> so `A: B` in a type context would basically amount to saying that "type A should inherit from type B"

It does mean `A` inherits from `B`, but only the trait bounds. `B` is a generic type parameter and all it basically is is a name and a trait bound and a lifetime.

However this does raise the question, should `A: B` also inherit the lifetime of `B`? In accordance to the usual `: Trait + 'a` syntax it would mean lifetimes are part of the trait bound and would be inherited.

That would be another use case for `B: Trait, A: B + 'a, B: 'b`, i.e. multiple trait bound definitions for the same type parameter. That would help define the structural relationships between type parameters. Of course cyclic inheritance needs to be detected.

> [@atagunov](#):
>
> Would it be easier to carve a syntax for this in `where` clause?

This seems like a very narrow path to follow, the semantic of the `,` is conflicting with that in the `<>` generic parameter context and I think that would be confusing (does this bound apply to `A` or not? In what context am I?). But those are just my first thoughts.

---

<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 22, 2021, 2:19pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/8 "2021-02-22T14:19:25Z")

</div>

How about nesting the generic parameters?

```rust
fn my_fn<
    'a,
    I,
    <A, B>: ReallyALotToType<'a, I>,
>(a: A, b: B)
{ ... }

```

---

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

</div>

> [@mankinskin](#):
>
> for traits with many type parameters it would still not be ideal... `trait Long<T, C, E, U>` , especially when there are more than two type parameters to be bounded.

The RFC as well as my example above demonstrates that trait aliases do intend to allow type parameters.

> [@mankinskin](#):
>
> to enable more of rust's generic programming capabilities. I think a big factor that is holding us back here is the syntax.

Citation needed.

---

<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, 2:21pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/10 "2021-02-22T14:21:07Z")

</div>

> [@H2CO3](#):
>
> f you were allowed to write `trait Long = Really<Item=I> + ALot<'a, I> + ToType` ,

It does seem that if a suitable syntax is to be found it will be after `where`. Another imperfect attempt:

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

```

---

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

</div>

That looks much better indeed.

---

<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 22, 2021, 2:25pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/12 "2021-02-22T14:25:03Z")

</div>

Now _that_, is a really great idea. Local trait aliases.

---

<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 22, 2021, 3:54pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/13 "2021-02-22T15:54:12Z")

</div>

Once (non-local) trait aliases hit stable, are there any great reasons not to just use them? I mean, we don't have local type aliases in generic signatures either. (Should we?)

---

<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, 4:13pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/14 "2021-02-22T16:13:12Z")

</div>

> [@jdahlstrom](#):
>
> Once (non-local) trait aliases hit stable, are there any great reasons not to just use them?

You'd end up with

> [@mankinskin](#):
>
> ```rust
> A: ReallyALotToType<'a, I>,
> B: ReallyALotToType<'a, I>,
> 
> ```

which is good but still arguably less nice than a local trait alias

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

...so if added to generic `fn`-s it should also work on generic `struct`-s, etc? Guess so

---

<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 22, 2021, 4:22pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/15 "2021-02-22T16:22:55Z")

</div>

Yes, I like that idea a lot. Also important that you can reuse the generic context for the local alias' definition, which is what you would not get with module-level trait aliases.

Also I realized that `B: Trait, A: B + 'a, B: 'b` does not really make sense, because type parameters are generally not ordered, so definition order should not matter. That is also where the other solution `where Alias = Trait<T>` makes more sense.

---

<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 22, 2021, 4:45pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/16 "2021-02-22T16:45:18Z")

</div>

> [@](#):
>
> A: B: Trait

although there is still this option, too. I can think of cases where `where Alias = NotThatMuch<'a>` is actually not worth introducing a new name.

```rust
fn my_fn<'a, A: X, B: X, C: X, D: X>(a: A, b: B, c: C, d: D)
    where X = NotThatMuch<'a>
{
    ...

```

Here a shorter syntax would be nice to have.

```rust
fn my_fn<'a, A: B: C: D: NotThatMuch<'a>>(a: A, b: B, c: C, d: D) {
    ...
}

```

I think this can work fine. In general, `:` is very loosely defined, so I don't think this would be surprising or ambiguous to anyone.

---

<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 22, 2021, 4:53pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/17 "2021-02-22T16:53:12Z")

</div>

Such cases are pretty rare though, most of the time you can use a single type parameter for all the variables you need, but sometimes you need to allow different types within the same trait bounds, and I don't see any reason not to support those cases.

---

<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 22, 2021, 6:19pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/18 "2021-02-22T18:19:18Z")

</div>

> [@H2CO3](#):
>
> `(A, B)` doesn't work because [it already means a tuple](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c9f211bbadd47673d5770c79a810f150).

That's of course correct, but makes me wonder whether it could cover a bunch of the scenarios, without adding anything new.

As a trivial example, `(A, B, C): Clone + Debug` works great.

---

<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 22, 2021, 6:46pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/19 "2021-02-22T18:46:48Z")

</div>

Oh wow, I did not know this.

> [@scottmcm](#):
>
> As a trivial example, `(A, B, C): Clone + Debug` works great.

hm.. but I guess this only works for "derivable" traits. it doesn't seem to work for something like:

```rust
(A, B): Fn(u32) -> u32

```

---

<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 22, 2021, 6:59pm UTC](https://internals.rust-lang.org/t/same-trait-bounds-for-multiple-type-parameters/14101/20 "2021-02-22T18:59:59Z")

</div>

Just as an example, this is what I am dealing with right now:

```rust
fn intersections<
    L: Clone,
    R: Clone,
    W: Fn(&Token<T>, &Token<T>) -> usize,
    LE: Fn(Vec<LoadedEdge>, Vec<LoadedEdge>) -> (Vec<LoadedEdge>, Vec<LoadedEdge>),
    RE: Fn(Vec<LoadedEdge>, Vec<LoadedEdge>) -> (Vec<LoadedEdge>, Vec<LoadedEdge>),
    LMI: Fn(EdgeMappingMatrix) -> Vec<L>,
    RMI: Fn(EdgeMappingMatrix) -> Vec<R>,
    P: Fn(NodeIndex, NodeIndex, NodeIndex, NodeIndex, usize, usize, usize, usize) -> bool,
    LC: Fn(Vec<L>) -> EdgeMappingMatrix,
    RC: Fn(Vec<R>) -> EdgeMappingMatrix,
    LMC: Fn(Vec<LoadedEdge>, EdgeMappingMatrix, Vec<LoadedEdge>) -> LoadedEdgeMapping,
    RMC: Fn(Vec<LoadedEdge>, EdgeMappingMatrix, Vec<LoadedEdge>) -> LoadedEdgeMapping,
    LZ: Fn(&mut LoadedEdgeMapping),
    RZ: Fn(&mut LoadedEdgeMapping),
>(
    #[allow(unused)] name: &str,
    #[allow(unused)] sec_name: &str,
    w_sel: W,
    ledge_sel: LE,
    redge_sel: RE,
    lmat_iter: LMI,
    rmat_iter: RMI,
    pred: P,
    lconstr: LC,
    rconstr: RC,
    lmap_ctr: LMC,
    rmap_ctr: RMC,
    ldezero: LZ,
    rdezero: RZ,
    lhs: Self,
    rhs: Self,
    dist: usize,
) -> Option<(Self, Self)>
{
    ...

```

So in here are some exact duplicates, but also some parameterized patterns, which I could implement a trait for, but this would honestly clutter the namespace too much and is not worth the one line saved. So actually it might even be useful to allow local trait aliases to be parameterized too:

```rust
fn intersections<M, L, R, LMI: MI<L>, RMI: MI<R>, ...>(...)
    where MI<S> = Fn(M) -> Vec<S>,
          ...
{
    ...

```

i.e. every local alias captures all independent type parameters in the surrounding scope (`MI` uses `M`), and can also introduce its own parameterized scope (`MI<S>`, `S` only visible in the local alias).

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