Async trait Send bounds- Why not infer associated types?

That is, given a trait like

trait Database {
    type FetchFut: Future<Output=String>;
    fn fetch_data(&self) -> Self::FetchFut;
}

to allow implementations like

struct MyDb;
impl Database for MyDb {
    type FetchFut = _;
    async fn fetch_data(&self) -> String { "foo".into() }
}

where the associated FetchFut is inferred. Then bounds can be applied to the associated type, without extra syntax

fn foo<F: Send>(d: &impl Database<FetchFut=F>) {}

And if Database wants the future of implementers to be Send, it can put that bound on FetchFut.

This creates very complicated situations around dynamic dispatch and memory management:

https://smallcultfollowing.com/babysteps/blog/2022/09/18/dyn-async-traits-part-8-the-soul-of-rust/

1 Like

That's true for the dyn case, but my suggestion is for static dispatch, which doesn't have this issue because the future's size is known at compile time.

It can also make it more difficult for Rustaceans to keep track of how various associated types relate to one another, as well as with their concrete impls.

Not so much in the associated type definitions themselves, but at use sites:

In this example, how do I know, without looking at the trait definition, that the return type of MyDB::fetch_data is actually an associated type?

That's fair! Though we kind of have this problem already with associated types if they are spelled out, eg

struct Foo(u32);
impl Deref for Foo {
    type Target = u32;
    fn deref(&self) -> &u32 { &self.0 }
}

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