sqlx icon indicating copy to clipboard operation
sqlx copied to clipboard

async_fn_in_trait (AFIT) usage

Open tgross35 opened this issue 6 months ago • 5 comments

I haven't seen it discussed anywhere, but could sqlx benefit from AFIT as-is?

This was recently released with 1.75 (2023-12-28). As I understand it, it would mean that some of the traits that look pretty messy:

pub trait Executor<'c>: Send + Debug + Sized {
    type Database: Database;

    fn fetch_optional<'e, 'q, E>(
        self,
        query: E
    ) -> Pin<Box<dyn Future<Output = Result<Option<<Self::Database as Database>::Row>, Error>> + Send + 'e>>
       where 'q: 'e,
             'c: 'e,
             E: 'q + Execute<'q, Self::Database>;
    // ...
}

Can now be written with a more understandable syntax, which also drops the Box<dyn ...> indirection:

pub trait Executor<'c>: Send + Debug + Sized {
    type Database: Database;

    async fn fetch_optional<'e, 'q, E>(
        self,
        query: E
    ) -> Result<Option<<Self::Database as Database>::Row>, Error>
       where 'q: 'e,
             'c: 'e,
             E: 'q + Execute<'q, Self::Database>;
    // ...
}

The blog post here has more information https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html. It seems like the limitations could make things less usable, but perhaps still beneficial?

Obviously putting this to use would be a MSRV break so it won't be usable anytime soon, but I am just curious if this has been looked at at all.

Thanks!

tgross35 avatar Jan 26 '24 08:01 tgross35

From what I understand, this would need to be:

pub trait Executor<'c>: Send + Debug + Sized {
    type Database: Database;

    fn fetch_optional<'e, 'q, E>(
        self,
        query: E
    ) -> impl Future<Output = Result<Option<<Self::Database as Database>::Row>, Error>> + Send + 'e
       where 'q: 'e,
             'c: 'e,
             E: 'q + Execute<'q, Self::Database>;
    // ...
}

This would be required to get the Send bound in there, but when implementing the trait, async fn can be used.

FSMaxB avatar Jan 26 '24 09:01 FSMaxB

In other words: The limitation mentioned in the release blog post doesn't apply, because sqlx already requires the futures to be Send anyways.

FSMaxB avatar Jan 26 '24 09:01 FSMaxB

This would be a fantastic improvement, I've found the current signatures very intimidating.

dave42w avatar Jan 26 '24 09:01 dave42w

This is a refactor we've been planning to do for a long time, we were just waiting for the feature to land in stable. And of course, to find the time to actually do it.

abonander avatar Jan 26 '24 09:01 abonander

Re. MSRV, I'll remind readers of our official policy: https://github.com/launchbadge/sqlx/blob/main/FAQ.md#what-versions-of-rust-does-sqlx-support-what-is-sqlxs-msrv

This refactor is a breaking change regardless, as it would change the return types of many public methods. They'd go from nameable boxed trait objects to unnameable impl Future types.

abonander avatar Feb 17 '24 02:02 abonander