How long have you been using the .await
syntax?
I’m just starting to explore how it works.
What code are you working on? How many lines of code? How complex? How old is the codebase? Can you post a link to it?
I’m experimenting with converting dodrio to use futures 0.3/async await.
What environment are you editing the code in? Do you have .await
syntax highlighting?
vim / no (it may do - I haven’t updated my packages for a while).
Summarize what happened, both the good and the bad. I’m particularly interested in:
How the new syntax feels over time.
The syntax feels good.
What happened when you were debugging problems (if any).
I’m having a lot of problems with lifetimes when debugging. The fact that async functions de-sugar to
async fn example(&self) { /* .. */ }
// becomes
fn example(&'a self) -> impl Future<Output = ()> + 'a
(specifically the + 'a
at the end) is a real pain. It means that i often have to write a lot of boilerplate e.g.
fn example(&self) -> impl Future<Output = Result<(), MyError>> {
// say I have something weak reference counted and I want a handle
let handle = match self.inner.upgrade() {
Some(v) => v,
None => return future::Either::Left(future::ready(Err(MyError)))
}
future::Either::Right(async move {
// here I have some code.
})
so I need to manually wrap my return in an enum to unify the types.
It may be that on balance the inferred lifetime bounds are worth it, I’m just finding it a pain.
Experiences from teaching others or from people coming from other languages without much Rust experience.
I haven’t taught anyone rust async.
Any other background information you think is relevant.
I’ve been using rust for quite a while, so my experiences will be different from a newcomer.
EDIT
I also find the generated documentation confusing:
here is the documentation for my async function
pub async fn with_component<'_, F, T>(
&'_ self,
f: F
) -> Result<T, VdomDroppedError>
And I have to remember that the lifetime _
is linking self
and the return value (which is hidden since we are in an async
function).
I think this will be a source of a lot of confusion (at least it was for me).
EDIT2
I’ve thought about this some more, and I think you have to tie the lifetime of the future to self, because none of the body is run until the future is polled. In this case the solution has to be compiler error messages and/or documentation, and suggesting the pattern where you include an async block in a non-async function somewhere prominent.
I would also teach async blocks before async functions. Otherwise, async functions will lull newcomers into a false sense of simplicity, and then confuse them when they start to get lifetime error messages, especially since the real types are hidden from the user in async functions.