Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Async Rust also ends up with these super nasty types involving Future that can't even be named half the time and you have to refer to them by existential types, like `impl Future<Output = Foo>`.

But these existential types can only be specified in function return or parameter position, so if you want to name a type for e.g.:

  let x = async { };
You can't! Because you can only refer to it as `impl Future<Output = ()>` but that's not allowed in a variable binding!


You're not wrong, but I don't really see the problem? Even well before async Rust, closures worked the same way with not being able to specify a concrete type, and `impl Trait` syntax didn't even exist for a while. Annotating local variable types is a way to fix certain things that would otherwise be ambiguous; it's a means to an end, only an end itself.


Ah that's true, but I think it ends up hairier when you combine the two together and have closures that are async, e.g.:

  let x = || -> i32 { 1 };  // fine
  let x = || -> impl Future<Output = i32> { async { 1 } };  // error: `impl Trait` only allowed in function and inherent method return types, not in closure return types
Unless I'm missing something, sometimes you do have to name the return type of an async closure if it's returning e.g Result<T, Box<dyn Error>>, and use of the ? operator means that the return type can't be inferred without an explicit annotation.


I think part of the disconnect is that that what you're calling an "async closure" is more directly an analog of a "regular" function that happens to return a future rather than an "async fn" declared function; you'd need similar syntactic boilerplate for annotating a function that's not declared as "async". Currently, there is no closure version of an "async fn" in Rust, but it's arguably not particularly necessary because you can use a Future as the async version of a closure in a lot of cases due to them being lazy already. For example, spawning a task with tokio just takes a Future, not a closure like spawning a sync thread.


You can annotate the return type inside the closure in those cases, for example:

    let x = || async {
        let file = std::fs::read_to_string("foo.txt")?;
        Ok::<_, Box<dyn std::error::Error>>(file)
    };




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: