rust-lang / rust-lang/rfcs

Universal quantification for types

Open
#2,413 5 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

Currently, we have for <'a>. I was thinking of expanding it into for <T: Trait>.

The use case is the following:

trait Trait {}

// This is implementation detail
struct Foo<T>(T);
impl<T> Trait for Foo<T> {}

// This is public API, foo takes a type and a closure that takes a Trait as input
pub fn foo<T, F: Fn(Foo<T>)>(t: T, f: F) {
    f(Foo(t))
}

(playground link)

Here, I don't want to expose the fact that F must take a Foo<T>. I want to expose the fact that F must take any Trait. But there's no way I can think of to encode this assertion in the Rust type system, currently.

So I was thinking of adding for <T: Trait> bound on types. As was pointed out to me, eg. for <T: Trait> Fn(T) wouldn't be object-safe. But I think that's something that could be useful nonetheless, as exposed by the corrected signature for foo below:

pub fn foo<T, F: for <P: Trait> Fn(P)>(t: T, f: F)

The actual use case that made this idea emerge was with tokio::Stream: I have a function like this:

pub fn bar<
    Stream,
    HandleErr,
    Callback: Fn(MapErr<Stream, HandleErr>) -> MapErr<Stream, HandleErr>
>(
    stream: Stream,
    err_cb: HandleErr,
    callback: Callback
)

Actually, this is a lucky case. Indeed, had I not directly passed the err_cb into stream.map_err, but instead passed eg. a closure, I'd have been completely unable to write the type… and would have had to re-write the closure type by hand just to be able to type it.

So, with the proposed for <T: Trait> idea, the function would look like this:

pub fn bar<Stream, HandleErr, Callback: for <S: Stream> Fn(S) -> S>(...)

What would be possible to pass into it would be (resuming with the toy example above):

// Template functions:
fn baz<T: Trait>(t: T) { }
foo(baz);

// If type inference permits, closures where the body uses only functions from `Trait`
foo(|x| ());

So if that's technically possible I think it'd be great. But I'm not sure it is? I guess it'd require monomorphization of the argument inside of the function body before knowing the size of the said argument, at least.

Anyway, would be glad to hear any opinion on this idea :)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the proposed for <T: Trait> syntax and the linked Rust playground example, then assess its interaction with generic closures, trait bounds, object safety, type inference, and monomorphization. Done means determining whether the proposal is technically feasible and what RFC-level design and constraints it requires.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.