# Too many type parameters, and complicated signatures

**URL:** <https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721>\
**Category:** language design\
**Created:** [July 13, 2020, 3:24pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721 "2020-07-13T15:24:42Z")\
**Posts on this page:** 11\
**Page:** 1

<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:** [July 13, 2020, 3:24pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/1 "2020-07-13T15:24:43Z")

</div>

(This isn't a proposal, but a description of a common problem I have and ideas as to how the language can solve it. Maybe other people have this problem, too.)

_The Setup_

The following is an issue I've been running into a lot, which I wonder if the language could do something about. Let's consider an unhypothetical scenario:

I have a library. It does crypto. It can't pull in something like ring because it's meant to run on SOCs with crypto acceleration in silicon. Thus, I wind up defining dozens of traits with names like `Rsa`, `Sha256`, `EccBuilder`, and so on, which are related by way of associated types. So far, this is a pretty standard Rust abstraction.

The problem is that the entry point for the library now has something like a dozen type parameters that both I, the library author, and my users, need to type out. We can agree that the following is line noise:

```rust
impl<Sha256, Rsa, Ed25519, Hmac, Aes, Rng, ...> for ...
  where <lots and lots of bounds> { ... }

```

The "standard" solution is to write this all down as associated types of a trait:

```rust
trait Crypto {
  type Sha256: Sha256;
  type Rsa: Rsa;
  // ...
}

```

Implementing this trait is a lot of boilerplate and requires creating a single-use ZST, which isn't too terrible, but can be a bit rough to do when you want to capture impl type parameters:

```rust
struct MyCrypto<Rsa>(PhantomData(fn() -> Rsa));
impl<Rsa> Crypto For MyCrypto<Rsa> {
    type Sha256 = MySha;
    type Rsa = Rsa;
}

impl<Rsa> ... {
    fn foo() -> MyStruct<MyCrypto<Rsa>>; // Requires T: Crypto.
}

```

Of course, the real version of this is worse, with many more type parameters.

* * *

_A Potential Solution_

I want to make this kind of API more ergonomic. I run into it a lot in code I need to write, and I can imagine code that has a lot of injection points (something like petgraph comes to mind) also runs into this problem.

This problem reminds me of the problem that Java's anonymous classes solve, so I tried to take that idea, apply it to this problem, and take it to its logical concluison.

What I would like to be able to write would be something like this:

```rust
impl<Rsa> ... {
  fn foo() -> MyStruct<impl Crypto { type Rsa = Rsa; type Sha256 = MySha; }>;
}

```

The production `impl $ident { $items }` in type position is intended to desugar into:

```rust
// In "scratch space", at item scope.
struct $anon;
impl $trait for $anon {
  $items
}
// In type position.
$anon

```

Of course, if $items or $trait reference any names of types or lifetimes in scope, those should be captured as type parameters on $anon. In the example above, `Rsa` is captured from `impl` scope.

One could imagine that `impl<'a> Trait<'a> { .. }` would result in a type implementing `for<'a> Trait<'a>`.

* * *

As far as I know, this isn't the kind of thing we can really do with macros (locally), because it's not possible to inject a temporary scope in which to define items while in type position.

I also feel like this is a focused solution that only solves one problem. I'm not sure how something like this could be cleanly generalized.

This general problem reminds me of Scala's "type lambdas", though those are more in the space of "I have an HKT parameter, I want to make a type constructor that fits it on the spot". The syntax is as follows:

```rust
class Foo[T[_]] { .. } // Foo has kind (type -> type) -> type.
def x: Foo[[V] => Map[String, V]] // Curried application of Map[_, _]

```

This isn't the same kind of problem (since Rust doesn't, and seems unlikely to ever get, true HKTs), but it does dig into the problem space of "I need to define a fairly simple type on the spot". The solutions all feel like they want to be some kind of "block expressions, but for types". Both my "anonymous impl" and Scala's type lambdas feel like they're getting at this concept.

Thoughts? Maybe there's something useful here for improving the ergonomics of complicated, type-level code.

---

<div class="post-metadata">

**Author:** ![matt1985](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matt1985/32/4772_2.png) [@matt1985](https://internals.rust-lang.org/u/matt1985)\
**Post date:** [July 13, 2020, 6:09pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/2 "2020-07-13T18:09:59Z")

</div>

One woraround you can use for traits that only have associated types is to define a marker type like `FooImpl` below, and use it everywhere (no need to define a new struct for every function).

To make defining the zero-sized type for a particular trait more ergonomic, one can define a `macro_rules!` macro, or an attribute macro, and use it once for each trait.

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

```rust
use std::fmt::Debug;
use std::marker::PhantomData;

pub fn get_foo() -> impl Foo<'static, u32, Bar = u8, Baz = u16, Qux = String> {
    FooImpl::NEW
}

pub trait Foo<'a, T> {
    type Bar: Debug;
    type Baz: Copy;
    type Qux: Clone;
}

pub struct FooImpl<'a, T, Bar, Baz, Qux>(PhantomData<fn() -> (&'a (), T, Bar, Baz, Qux)>);

impl<'a, T, Bar, Baz, Qux> Foo<'a, T> for FooImpl<'a, T, Bar, Baz, Qux>
where
    Bar: Debug,
    Baz: Copy,
    Qux: Clone,
{
    type Bar = Bar;
    type Baz = Baz;
    type Qux = Qux;
}

impl<'a, T, Bar, Baz, Qux> FooImpl<'a, T, Bar, Baz, Qux> {
    pub const NEW: Self = Self(PhantomData);
}

```

---

<div class="post-metadata">

**Author:** ![djc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/djc/32/1592_2.png) [@djc](https://internals.rust-lang.org/u/djc)\
**Post date:** [July 14, 2020, 7:05am UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/3 "2020-07-14T07:05:42Z")

</div>

This should also get better with type alias impl trait, I guess?

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [July 14, 2020, 9:04am UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/4 "2020-07-14T09:04:20Z")

</div>

And implied bounds, and trait aliases, just off the top of my head.

This is definitely a problem space where we currently need more implementation and stabilization to get done before it makes much sense to design additional changes.

---

<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:** [July 14, 2020, 3:04pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/5 "2020-07-14T15:04:01Z")

</div>

Indeed, that is the state of the art that I've had to use lately. =)

It does seem like there's a few related features pending stabilization that would make this mindly less painful, though I don't think that any of the mentioned features (existential type aliases, implied bounds, and bound/trait aliases) make this particular case of make-me-a-witness-on-demand particularly easier.

I think that what I almost want is some kind of "product kind", analogous to how we can build up product types for passing many values around as a cohesive unit. The mental image I keep coming back to is the desire to write down a struct whose fields are all of "type" `type`. Ostensibly that's what the tuple type constructors are, but there's no good "struct-like" equivalent, where you can do `.`-syntax access instead of what is essentially pattern matching in an `impl` declaration.

---

<div class="post-metadata">

**Author:** ![Ixrec](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ixrec/32/6754_2.png) [@Ixrec](https://internals.rust-lang.org/u/Ixrec)\
**Post date:** [July 14, 2020, 3:07pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/6 "2020-07-14T15:07:55Z")

</div>

> [@mcy](#):
>
> though I don't think that any of the mentioned features (existential type aliases, implied bounds, and bound/trait aliases) make this particular case of make-me-a-witness-on-demand particularly easier.

If the clarification helps: I do agree with this.

I just think it'll be impractically difficult to design a proper solution to this before any of those other features land, much less convince anyone it's the best solution (and better than doing nothing).

Come to think of it, GATs might be helpful here too.

---

<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:** [July 14, 2020, 3:12pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/7 "2020-07-14T15:12:17Z")

</div>

> [@Ixrec](#):
>
> I just think it'll be impractically difficult to design a proper solution to this before any of those other features land, much less convince anyone it's the best solution (and better than doing nothing).

Oh, I might have misread. Yeah, the type system does have a lot of things in flight, which is why this post is intentionally _not_ a proposal, but more like... aspirational note-taking. I am running on the assumption that all of those features will be stabilized close to the form currently implemented in the nightly compiler, and I don't immediately feel think they're likely to affect the design. But, as you say, it's hard to tell at this stage.

---

<div class="post-metadata">

**Author:** ![robinm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/robinm/32/6255_2.png) [@robinm](https://internals.rust-lang.org/u/robinm)\
**Post date:** [July 15, 2020, 4:49pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/8 "2020-07-15T16:49:46Z")

</div>

Using GAT, wouldn't this become:

```rust
trait Sha256_ { /* ... */ }
trait Rsa_ { /* ... */ }

trait Crypto<Sha256, Rsa, /* ... */ >
where
    Sha256 : Sha256_,
    Rsa: Rsa_,
{
  // ...
}

```

Which means that you could write

```rust
impl<Rsa> ... {
  fn foo() -> MyStruct<impl Crypto<Rsa = Rsa_, Sha256 = MySha>>;
}

```

Notes:

- I think the final `_` could be removed (I think that the grammar isn't ambiguous if the types parameters and the trait share the same name.
- I didn't checked the GAT RFC, but I think it should be possible to access to `Crypto::Sha256` (and get `MySha`). If it's not possible directly, it should be easy to add a `type Sha256: Sha256_ = Sha256` in the trait `Crypto`.

* * *

Totally unrelated, but what is the antonym of the word "leading"? `_foo_` as both a leading and a ??? underscore. Same question for in-the-middle (`foo_and_bar` has two ??? underscores).

---

<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:** [July 15, 2020, 4:55pm UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/9 "2020-07-15T16:55:25Z")

</div>

> [@robinm](#):
>
> Totally unrelated, but what is the antonym of the word "leading"? `_foo_` as both a leading and a ??? underscore. Same question for in-the-middle ( `foo_and_bar` has two ??? underscores).

leading/trailing underscores. `snake_case` I'd probably say as central or internal underscores if I had to, but probably just say snake case.

---

<div class="post-metadata">

**Author:** ![robinm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/robinm/32/6255_2.png) [@robinm](https://internals.rust-lang.org/u/robinm)\
**Post date:** [July 16, 2020, 10:03am UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/10 "2020-07-16T10:03:00Z")

</div>

Thanks a lot!

---

<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:** [October 14, 2020, 10:12am UTC](https://internals.rust-lang.org/t/too-many-type-parameters-and-complicated-signatures/12721/11 "2020-10-14T10:12:45Z")

</div>

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