Real async closures don't work with associated types in traits #289
Replies: 2 comments
-
|
Thanks for sharing these information. That's useful and welcome. Although as you wrote that's not an issue with diesel-async, so I converted this to a discussion instead. Ultimately this is still a workaround for a language limitation (not being able to specify trait bounds for the future returned by an |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @inga-lovinde. I was stuck on this for a few days, but got it working now. Posted a solution on StackOverflow. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Setup
Versions
Problem Description
This is not a problem in diesel_async, but something that people using diesel_async are likely to encounter, so I want to document this here just in case for the other users, along with the possible workaround. Maybe, if you ever decide to make
AsyncFuncpublic, you'll want to adapt this workaround.The problem is that building code around diesel_async in codebases with wrappers around connections and transactions still requires one to use scoped futures, or to use a different set of tricks;
AsyncFuncdoesn't work there.What are you trying to accomplish?
To use new
AsyncFunc(as introduced in #284) in higher-level code consuming diesel_async, in order to have connection wrappers and transaction wrappers performing some additional work, with method similar to.transactionand calling diesel_async'stransactionunder the hood.What is the expected output?
Code compiles.
What is the actual output?
Rust produces compile-time errors: even for identical trait and implementation function signatures (including trait bounds), it considers trait bounds on arguments to not be equivalent when these trait bounds (1) use trait associated types and (2) constrain them to traits with explicit associated types on their own.
I cannot describe it in a way that makes sense because I'm not a rust expert, so just see the examples below.
This might be a bug in rustc, but I don't know rustc enough to file a bug there (maybe that's the same bug as reported in rust-lang/rust#137639 ?), and in #284 you seemed to be interested in other people's workarounds for rustc weirdness such as lcnr/random-rust-snippets#26 , so maybe this will help too.
Are you seeing any additional errors?
No
Steps to reproduce
This self-contained (can be just inserted into rust playground) code does not compile:
The errors are:
Note that the definition of
AsyncFuncin the snippet above is just copied as is from diesel_async without any changes, and that in this snippet we don't even implementAsyncFuncfor anything.Note that the signature of
transactionmethod is copied as is from diesel_async (including the constraints) with one changes: instead of&'r mut Self,Fis expected to receive&'r mut Self::Transaction.Replacing
Self::TransactionwithSelf(or with any fixed type such asu8) solves the compile-time errors.Removing
+ AsyncFunc<...>constraint onFalso solves the compile-time errors.Updating
AsyncFuncdefinition to sayand removing
, Fut: Sendtrait bound fromtransactionmethod signature does not solve the compile-time errors.What does solve the compile-time errors while preserving the benefits
AsyncFuncbrings us (i.e. constraining future returned byFto beSend) is removing explicit associated type fromAsyncFuncand using implicit associated type instead (by having a function that returnsimpl ...):This snippet does compile successfully without errors.
The drawback is that, inside
transactionimplementation, we'd have to invoke callback withcallback.call(transaction)instead ofcallback(transaction)in order to get a future that isSend.But I think that's a small price to pay for a working workaround.
Checklist
Beta Was this translation helpful? Give feedback.
All reactions