async-fundamentals-initiative icon indicating copy to clipboard operation
async-fundamentals-initiative copied to clipboard

Attributes to indicate Send/Sync bound for Future generated in Static Async Trait

Open umgefahren opened this issue 2 years ago • 3 comments

Motivation

As previously discussed it's a debated issue how to express Send/Sync bounds on the generated associated types for async methods. As I understand it, this issue will be resolved in the future. I'm currently writing a library which might profit from a way to express the bound so I would appreciate a solution for the problem to be stabilized along with static-async-trait.

Details

I'm currently developing a macro library that tries to implement about the same desugaring as described in the RFC. I came up with a solution for this using attributes on the trait methods.

Example

struct Foo;

trait Bar {
    #[send]
    async fn wait(&self);
}

impl Bar for Foo {
    async fn wait(&self) {
        todo!()
    }
}

// this trait can now be used with tokio::spawn
async fn spawn_trait<T: Bar + Sync + Send + 'static>(foo: T) {
    let handle = tokio::spawn(async move {
        foo.wait().await;
    });
    handle.await;
}

A method with a body that has to be Send is just annotated with #[send] and for Sync it's just annotated with #[sync].

An attribute would not be that unusual. Derive default enum uses an attribute as well.

Caveats

How would this appear in rustdoc?

I would appreciate your feedback

umgefahren avatar Jul 25 '22 17:07 umgefahren

Some additional thoughts:

I saw a proposal that suggested introducing additional, potentially complex, syntax. This aligns more with the general way how Rust deals with types, traits and especially trait constraints. Despite this being a huge implementation undertaking it wouldn't improve readability and make Rust even more complex.

In my opinion this is also a counter argument for just solving the issue by suggesting manual desugarization.

Since one can already do that as soon as GATs and impl traits are stabilized, this feature should be considered more as a quality of life improvement or syntactic sugar. As such I would consider introducing new as syntax overkill. Solving this in a fashion that resembles the macros currently used would benefit from better accessibility and readability. It would also speed up adaption once it's stabilized.

umgefahren avatar Jul 25 '22 19:07 umgefahren

A downside of this approach is that Send/Sync-ness has to be decided on the trait. This is especially difficult for standard traits like AsyncIterator, and we don't want to have multiple versions of each trait (like we already do for async/sync).

tmandry avatar Aug 03 '22 00:08 tmandry

Thanks for the response!

I get why it was considered to introduce new syntax. However it might be useful to let the trait decide in some situations.

However I see why my proposal is unfit.

umgefahren avatar Aug 06 '22 17:08 umgefahren